From 56d5019b945d267a940e9aeb33efa0c95f3136ef Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Tue, 24 Nov 2015 22:09:50 -0800 Subject: [PATCH 01/19] Updates to examples and documentation. --- ...DCfwd.py => Forward_BasicDirectCurrent.py} | 4 ++- .../{Linear.py => Inversion_Linear.py} | 23 +++++++------ SimPEG/Examples/Mesh_QuadTree_Create.py | 18 +++++++++++ SimPEG/Examples/Mesh_ThreeMeshes.py | 24 ++++++++++++++ SimPEG/Examples/__init__.py | 10 +++++- SimPEG/Mesh/TreeMesh.py | 12 ++++--- SimPEG/Utils/__init__.py | 1 + SimPEG/Utils/codeutils.py | 32 +++++++++++++++++++ docs/api_Examples.rst | 11 +++++-- docs/api_Mesh.rst | 18 ++--------- docs/examples/Forward_BasicDirectCurrent.rst | 17 ++++++++++ docs/examples/Inversion_Linear.rst | 17 ++++++++++ docs/examples/Mesh_QuadTree_Create.rst | 17 ++++++++++ docs/examples/Mesh_ThreeMeshes.rst | 17 ++++++++++ tests/examples/test_examples.py | 21 +++++++----- 15 files changed, 201 insertions(+), 41 deletions(-) rename SimPEG/Examples/{DCfwd.py => Forward_BasicDirectCurrent.py} (98%) rename SimPEG/Examples/{Linear.py => Inversion_Linear.py} (78%) create mode 100644 SimPEG/Examples/Mesh_QuadTree_Create.py create mode 100644 SimPEG/Examples/Mesh_ThreeMeshes.py create mode 100644 docs/examples/Forward_BasicDirectCurrent.rst create mode 100644 docs/examples/Inversion_Linear.rst create mode 100644 docs/examples/Mesh_QuadTree_Create.rst create mode 100644 docs/examples/Mesh_ThreeMeshes.rst diff --git a/SimPEG/Examples/DCfwd.py b/SimPEG/Examples/Forward_BasicDirectCurrent.py similarity index 98% rename from SimPEG/Examples/DCfwd.py rename to SimPEG/Examples/Forward_BasicDirectCurrent.py index 33e7aad5..a3c9ff97 100644 --- a/SimPEG/Examples/DCfwd.py +++ b/SimPEG/Examples/Forward_BasicDirectCurrent.py @@ -12,7 +12,6 @@ def run(plotIt=True): tM = Mesh.TensorMesh(sz) # Curvilinear Mesh rM = Mesh.CurvilinearMesh(Utils.meshutils.exampleLrmGrid(sz,'rotate')) - # Step2: Direct Current (DC) operator def DCfun(mesh, pts): D = mesh.faceDiv @@ -39,6 +38,7 @@ def run(plotIt=True): phirM = AinvrM*rhsrM if not plotIt: return + #Step4: Making Figure fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2)) label = ["(a)", "(b)"] @@ -69,7 +69,9 @@ def run(plotIt=True): else: axes[i].set_ylabel(" ") axes[i].set_xlabel("x") + plt.show() if __name__ == '__main__': + Utils._makeExample(__file__) run() diff --git a/SimPEG/Examples/Linear.py b/SimPEG/Examples/Inversion_Linear.py similarity index 78% rename from SimPEG/Examples/Linear.py rename to SimPEG/Examples/Inversion_Linear.py index b065682b..2446bd58 100644 --- a/SimPEG/Examples/Linear.py +++ b/SimPEG/Examples/Inversion_Linear.py @@ -23,7 +23,9 @@ class LinearProblem(Problem.BaseProblem): return self.G.T.dot(v) -def run(N, plotIt=True): +def run(N=100, plotIt=True): + np.random.seed(1) + mesh = Mesh.TensorMesh([N]) nk = 20 @@ -52,7 +54,7 @@ def run(N, plotIt=True): reg = Regularization.Tikhonov(mesh) dmis = DataMisfit.l2_DataMisfit(survey) - opt = Optimization.InexactGaussNewton(maxIter=20) + opt = Optimization.InexactGaussNewton(maxIter=35) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) beta = Directives.BetaSchedule() betaest = Directives.BetaEstimate_ByEig() @@ -63,16 +65,19 @@ def run(N, plotIt=True): if plotIt: import matplotlib.pyplot as plt - plt.figure(1) - for i in range(prob.G.shape[0]): - plt.plot(prob.G[i,:]) - plt.figure(2) - plt.plot(M.vectorCCx, survey.mtrue, 'b-') - plt.plot(M.vectorCCx, mrec, 'r-') + fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2)) + for i in range(prob.G.shape[0]): + axes[0].plot(prob.G[i,:]) + axes[0].set_title('Columns of matrix G') + + axes[1].plot(M.vectorCCx, survey.mtrue, 'b-') + axes[1].plot(M.vectorCCx, mrec, 'r-') + axes[1].legend(('True Model', 'Recovered Model')) plt.show() return prob, survey, mesh, mrec if __name__ == '__main__': - run(100) + Utils._makeExample(__file__) + run() diff --git a/SimPEG/Examples/Mesh_QuadTree_Create.py b/SimPEG/Examples/Mesh_QuadTree_Create.py new file mode 100644 index 00000000..f4417855 --- /dev/null +++ b/SimPEG/Examples/Mesh_QuadTree_Create.py @@ -0,0 +1,18 @@ +from SimPEG import * + +def run(plotIt=True): + from SimPEG import Mesh, np + M = Mesh.TreeMesh([32,32]) + M.refine(3) + def function(cell): + xyz = cell.center + for i in range(3): + if np.abs(np.sin(xyz[0]*np.pi*2)*0.5 + 0.5 - xyz[1]) < 0.2*i: + return 6-i + return 0 + M.refine(function); + if plotIt: M.plotGrid(showIt=True) + +if __name__ == '__main__': + Utils._makeExample(__file__) + run() diff --git a/SimPEG/Examples/Mesh_ThreeMeshes.py b/SimPEG/Examples/Mesh_ThreeMeshes.py new file mode 100644 index 00000000..2fc7fa8d --- /dev/null +++ b/SimPEG/Examples/Mesh_ThreeMeshes.py @@ -0,0 +1,24 @@ +from SimPEG import * + +def run(plotIt=True): + sz = [16,16] + tM = Mesh.TensorMesh(sz) + qM = Mesh.TreeMesh(sz) + qM.refine(lambda cell: 4 if np.sqrt(((np.r_[cell.center]-0.5)**2).sum()) < 0.4 else 3) + rM = Mesh.CurvilinearMesh(Utils.meshutils.exampleLrmGrid(sz,'rotate')) + + if plotIt: + import matplotlib.pyplot as plt + fig, axes = plt.subplots(1,3,figsize=(14,5)) + opts = {} + tM.plotGrid(ax=axes[0], **opts) + axes[0].set_title('TensorMesh') + qM.plotGrid(ax=axes[1], **opts) + axes[1].set_title('TreeMesh') + rM.plotGrid(ax=axes[2], **opts) + axes[2].set_title('CurvilinearMesh') + plt.show() + +if __name__ == '__main__': + Utils._makeExample(__file__) + run() diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index 3fec0b99..53b1f9a8 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -1 +1,9 @@ -import Linear, DCfwd +# This will import everything in the directory into this file +from os import path as p +from glob import glob +__all__ = [] +for x in glob(p.join(p.dirname(__file__), '*.py')): + if not p.basename(x).startswith('__'): + __import__(p.basename(x)[:-3], globals(), locals()) + __all__ += [p.basename(x)] +del glob, p, x diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 1e6c91c0..69a44fdc 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -1960,7 +1960,7 @@ class TreeMesh(BaseTensorMesh, InnerProducts): def plotGrid(self, ax=None, showIt=False, grid=True, - cells=True, cellLine=False, + cells=False, cellLine=False, nodes=False, facesX=False, facesY=False, facesZ=False, edgesX=False, edgesY=False, edgesZ=False): @@ -2009,6 +2009,8 @@ class TreeMesh(BaseTensorMesh, InnerProducts): if facesY: ax.plot(self._gridFy[self._hangingFy.keys(),0], self._gridFy[self._hangingFy.keys(),1], 'gs', ms=10, mfc='none', mec='g') ax.plot(self._gridFy[:,0], self._gridFy[:,1], 'g^') + ax.set_xlabel('x1') + ax.set_ylabel('x2') elif self.dim == 3: if cells: ax.plot(self.gridCC[:,0], self.gridCC[:,1], 'r.', zs=self.gridCC[:,2]) @@ -2056,7 +2058,6 @@ class TreeMesh(BaseTensorMesh, InnerProducts): ind = [key, hf[0]] ax.plot(self._gridEx[ind,0], self._gridEx[ind,1], 'k:', zs=self._gridEx[ind,2]) - if edgesY: ax.plot(self._gridEy[:,0], self._gridEy[:,1], 'k<', zs=self._gridEy[:,2]) ax.plot(self._gridEy[self._hangingEy.keys(),0], self._gridEy[self._hangingEy.keys(),1], 'ks', ms=10, mfc='none', mec='k', zs=self._gridEy[self._hangingEy.keys(),2]) @@ -2072,7 +2073,10 @@ class TreeMesh(BaseTensorMesh, InnerProducts): for hf in self._hangingEz[key]: ind = [key, hf[0]] ax.plot(self._gridEz[ind,0], self._gridEz[ind,1], 'k:', zs=self._gridEz[ind,2]) - + ax.set_xlabel('x1') + ax.set_ylabel('x2') + ax.set_zlabel('x3') + ax.grid(True) if showIt:plt.show() def plotImage(self, I, ax=None, showIt=True, grid=False): @@ -2191,7 +2195,7 @@ class Cell(object): @property def center(self): if getattr(self, '_center', None) is None: - self._center = self.mesh._cellC(self._pointer) + self._center = np.array(self.mesh._cellC(self._pointer)) return self._center @property def h(self): return self.mesh._cellH(self._pointer) diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index 5280ae79..67e1b117 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -1,5 +1,6 @@ from matutils import * from codeutils import * +from codeutils import _makeExample from meshutils import exampleLrmGrid, meshTensor, closestPoints, readUBCTensorMesh, writeUBCTensorMesh, writeUBCTensorModel, readVTRFile, writeVTRFile from curvutils import volTetra, faceInfo, indexCube from interputils import interpmat diff --git a/SimPEG/Utils/codeutils.py b/SimPEG/Utils/codeutils.py index 4a9a28a7..fef34282 100644 --- a/SimPEG/Utils/codeutils.py +++ b/SimPEG/Utils/codeutils.py @@ -227,3 +227,35 @@ def requires(var): return requiresVarWrapper return requiresVar + +def _makeExample(filePath): + + import os + name = filePath.split(os.path.sep)[-1][:-3] + out = """.. _examples_%s: + +.. ------------------------------ .. +.. THIS FILE IS AUTO GENEREATED .. +.. ------------------------------ .. + +%s +%s + +.. plot:: + + from SimPEG import Examples + Examples.%s.run() + +.. literalinclude:: ../../SimPEG/Examples/%s.py + :language: python + :linenos: +"""%(name,name.replace('_',' '),'='*len(name),name,name) + + rst = os.path.sep.join((filePath.split(os.path.sep)[:-3] + ['docs', 'examples', name + '.rst'])) + + f = open(rst, 'w') + f.write(out) + f.close() + + + diff --git a/docs/api_Examples.rst b/docs/api_Examples.rst index 214dd8e1..68589fb3 100644 --- a/docs/api_Examples.rst +++ b/docs/api_Examples.rst @@ -3,8 +3,15 @@ Examples ******** -Forward problem -=============== +.. toctree:: + :maxdepth: 1 + :glob: + + examples/* + + +External Notebooks +================== * `Example 1: Direct Current `_ * `Example 2: Seismic-Acoustic `_ diff --git a/docs/api_Mesh.rst b/docs/api_Mesh.rst index 7bf398b1..a7f7abae 100644 --- a/docs/api_Mesh.rst +++ b/docs/api_Mesh.rst @@ -23,23 +23,9 @@ the implementations. .. plot:: - from SimPEG import Mesh, Utils, np - import matplotlib.pyplot as plt - sz = [10,10] - tM = Mesh.TensorMesh(sz) - qM = Mesh.TreeMesh(sz) - qM.refine(lambda X: 1 if np.sqrt(((X-0.5)**2).sum()) < 0.3 else 0) - rM = Mesh.CurvilinearMesh(Utils.meshutils.exampleLrmGrid(sz,'rotate')) + from SimPEG import Examples + Examples.Mesh_ThreeMeshes.run() - fig, axes = plt.subplots(1,3,figsize=(14,5)) - opts = {} - tM.plotGrid(ax=axes[0], **opts) - axes[0].set_title('TensorMesh') - qM.plotGrid(ax=axes[1], **opts) - axes[1].set_title('TreeMesh') - rM.plotGrid(ax=axes[2], **opts) - axes[2].set_title('CurvilinearMesh') - plt.show() Variable Locations and Terminology diff --git a/docs/examples/Forward_BasicDirectCurrent.rst b/docs/examples/Forward_BasicDirectCurrent.rst new file mode 100644 index 00000000..6fc816e7 --- /dev/null +++ b/docs/examples/Forward_BasicDirectCurrent.rst @@ -0,0 +1,17 @@ +.. _examples_Forward_BasicDirectCurrent: + +.. ------------------------------ .. +.. THIS FILE IS AUTO GENEREATED .. +.. ------------------------------ .. + +Forward BasicDirectCurrent +========================== + +.. plot:: + + from SimPEG import Examples + Examples.Forward_BasicDirectCurrent.run() + +.. literalinclude:: ../../SimPEG/Examples/Forward_BasicDirectCurrent.py + :language: python + :linenos: diff --git a/docs/examples/Inversion_Linear.rst b/docs/examples/Inversion_Linear.rst new file mode 100644 index 00000000..637315ae --- /dev/null +++ b/docs/examples/Inversion_Linear.rst @@ -0,0 +1,17 @@ +.. _examples_Inversion_Linear: + +.. ------------------------------ .. +.. THIS FILE IS AUTO GENEREATED .. +.. ------------------------------ .. + +Inversion Linear +================ + +.. plot:: + + from SimPEG import Examples + Examples.Inversion_Linear.run() + +.. literalinclude:: ../../SimPEG/Examples/Inversion_Linear.py + :language: python + :linenos: diff --git a/docs/examples/Mesh_QuadTree_Create.rst b/docs/examples/Mesh_QuadTree_Create.rst new file mode 100644 index 00000000..644593d5 --- /dev/null +++ b/docs/examples/Mesh_QuadTree_Create.rst @@ -0,0 +1,17 @@ +.. _examples_Mesh_QuadTree_Create: + +.. ------------------------------ .. +.. THIS FILE IS AUTO GENEREATED .. +.. ------------------------------ .. + +Mesh QuadTree Create +==================== + +.. plot:: + + from SimPEG import Examples + Examples.Mesh_QuadTree_Create.run() + +.. literalinclude:: ../../SimPEG/Examples/Mesh_QuadTree_Create.py + :language: python + :linenos: diff --git a/docs/examples/Mesh_ThreeMeshes.rst b/docs/examples/Mesh_ThreeMeshes.rst new file mode 100644 index 00000000..948398a7 --- /dev/null +++ b/docs/examples/Mesh_ThreeMeshes.rst @@ -0,0 +1,17 @@ +.. _examples_Mesh_ThreeMeshes: + +.. ------------------------------ .. +.. THIS FILE IS AUTO GENEREATED .. +.. ------------------------------ .. + +Mesh ThreeMeshes +================ + +.. plot:: + + from SimPEG import Examples + Examples.Mesh_ThreeMeshes.run() + +.. literalinclude:: ../../SimPEG/Examples/Mesh_ThreeMeshes.py + :language: python + :linenos: diff --git a/tests/examples/test_examples.py b/tests/examples/test_examples.py index 1fcf05f5..baddb6db 100644 --- a/tests/examples/test_examples.py +++ b/tests/examples/test_examples.py @@ -1,17 +1,22 @@ import unittest import sys -from SimPEG.Examples import Linear, DCfwd +from SimPEG import Examples import numpy as np -class TestLinear(unittest.TestCase): - def test_running(self): - Linear.run(100, plotIt=False) +def get_test(test): + def func(self): + print '\nTesting %s.run(plotIt=False)\n'%test + getattr(Examples, test).run(plotIt=False) self.assertTrue(True) + return func +attrs = dict() +tests = [_ for _ in dir(Examples) if not _.startswith('_')] +for test in tests: + attrs['test_'+test] = get_test(test) + + +TestExamples = type('TestExamples', (unittest.TestCase,), attrs) -class TestDCfwd(unittest.TestCase): - def test_running(self): - DCfwd.run(plotIt=False) - self.assertTrue(True) if __name__ == '__main__': unittest.main() From bcfe9040154812fe4ed995038dca865fda387ab3 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Wed, 25 Nov 2015 08:26:27 -0800 Subject: [PATCH 02/19] remove test from the name in examples. --- tests/examples/test_examples.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/examples/test_examples.py b/tests/examples/test_examples.py index baddb6db..48cbaa65 100644 --- a/tests/examples/test_examples.py +++ b/tests/examples/test_examples.py @@ -3,7 +3,7 @@ import sys from SimPEG import Examples import numpy as np -def get_test(test): +def get(test): def func(self): print '\nTesting %s.run(plotIt=False)\n'%test getattr(Examples, test).run(plotIt=False) @@ -12,8 +12,8 @@ def get_test(test): attrs = dict() tests = [_ for _ in dir(Examples) if not _.startswith('_')] for test in tests: - attrs['test_'+test] = get_test(test) - + attrs['test_'+test] = get(test) +del get, tests, _ TestExamples = type('TestExamples', (unittest.TestCase,), attrs) From 06c66f6392ce4bd2e4517833df970f99d1c92982 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Wed, 25 Nov 2015 13:27:35 -0800 Subject: [PATCH 03/19] Addresses #183: Import errors for tree mesh --- SimPEG/Mesh/TreeMesh.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 1e6c91c0..f7a438ce 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -96,7 +96,13 @@ from mpl_toolkits.mplot3d import Axes3D import matplotlib.colors as colors import matplotlib.cm as cmx -import TreeUtils +try: + import TreeUtils + _IMPORT_TREEUTILS = True +except Exception, e: + _IMPORT_TREEUTILS = False + + from InnerProducts import InnerProducts from TensorMesh import TensorMesh, BaseTensorMesh import time @@ -108,6 +114,8 @@ class TreeMesh(BaseTensorMesh, InnerProducts): _meshType = 'TREE' def __init__(self, h, x0=None, levels=None): + if not _IMPORT_TREEUTILS: + raise Exception('Could not import the Cython code to run the TreeMesh Try:.\n\npython setup.py build_ext --inplace') assert type(h) is list, 'h must be a list' assert len(h) in [2,3], "There is only support for TreeMesh in 2D or 3D." From be3667b4abee8f19cc4ae1a23663ec083bf056c9 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Wed, 25 Nov 2015 16:03:08 -0800 Subject: [PATCH 04/19] New Examples - Put all examples in same directory - Make a single test - use __init__.py to create the docs automatically --- .travis.yml | 1 - SimPEG/EM/Examples/__init__.py | 1 - .../EM_FDEM_1D_Inversion.py} | 7 +++ .../FLOW_Richards_1D_Celia1990.py} | 34 +++++++++++ SimPEG/Examples/Forward_BasicDirectCurrent.py | 1 - SimPEG/Examples/Inversion_Linear.py | 53 +++++++++------- SimPEG/Examples/Mesh_Basic_PlotImage.py | 46 ++++++++++++++ ...esh_ThreeMeshes.py => Mesh_Basic_Types.py} | 8 ++- ...ee_Create.py => Mesh_QuadTree_Creation.py} | 14 ++++- SimPEG/Examples/Mesh_QuadTree_HangingNodes.py | 32 ++++++++++ SimPEG/Examples/Mesh_Tensor_Creation.py | 35 +++++++++++ SimPEG/Examples/__init__.py | 60 ++++++++++++++++++- SimPEG/FLOW/Examples/__init__.py | 1 - SimPEG/Mesh/TreeMesh.py | 39 +++++++----- SimPEG/Utils/__init__.py | 1 - SimPEG/Utils/codeutils.py | 32 ---------- docs/examples/EM_FDEM_1D_Inversion.rst | 26 ++++++++ docs/examples/FLOW_Richards_1D_Celia1990.rst | 52 ++++++++++++++++ docs/examples/Forward_BasicDirectCurrent.rst | 10 +++- docs/examples/Inversion_Linear.rst | 19 ++++-- docs/examples/Mesh_Basic_PlotImage.rst | 27 +++++++++ docs/examples/Mesh_Basic_Types.rst | 26 ++++++++ docs/examples/Mesh_QuadTree_Create.rst | 17 ------ docs/examples/Mesh_QuadTree_Creation.rst | 31 ++++++++++ docs/examples/Mesh_QuadTree_HangingNodes.rst | 31 ++++++++++ docs/examples/Mesh_Tensor_Creation.rst | 43 +++++++++++++ docs/examples/Mesh_ThreeMeshes.rst | 17 ------ tests/em/examples/__init__.py | 11 ---- tests/em/examples/test_Examples.py | 10 ---- tests/flow/test_examples.py | 12 ---- 30 files changed, 543 insertions(+), 154 deletions(-) delete mode 100644 SimPEG/EM/Examples/__init__.py rename SimPEG/{EM/Examples/CylInversion.py => Examples/EM_FDEM_1D_Inversion.py} (96%) rename SimPEG/{FLOW/Examples/Celia1990.py => Examples/FLOW_Richards_1D_Celia1990.py} (54%) create mode 100644 SimPEG/Examples/Mesh_Basic_PlotImage.py rename SimPEG/Examples/{Mesh_ThreeMeshes.py => Mesh_Basic_Types.py} (82%) rename SimPEG/Examples/{Mesh_QuadTree_Create.py => Mesh_QuadTree_Creation.py} (50%) create mode 100644 SimPEG/Examples/Mesh_QuadTree_HangingNodes.py create mode 100644 SimPEG/Examples/Mesh_Tensor_Creation.py delete mode 100644 SimPEG/FLOW/Examples/__init__.py create mode 100644 docs/examples/EM_FDEM_1D_Inversion.rst create mode 100644 docs/examples/FLOW_Richards_1D_Celia1990.rst create mode 100644 docs/examples/Mesh_Basic_PlotImage.rst create mode 100644 docs/examples/Mesh_Basic_Types.rst delete mode 100644 docs/examples/Mesh_QuadTree_Create.rst create mode 100644 docs/examples/Mesh_QuadTree_Creation.rst create mode 100644 docs/examples/Mesh_QuadTree_HangingNodes.rst create mode 100644 docs/examples/Mesh_Tensor_Creation.rst delete mode 100644 docs/examples/Mesh_ThreeMeshes.rst delete mode 100644 tests/em/examples/__init__.py delete mode 100644 tests/em/examples/test_Examples.py delete mode 100644 tests/flow/test_examples.py diff --git a/.travis.yml b/.travis.yml index c2c672bf..b9826bab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ python: sudo: false env: - - TEST_DIR=tests/em/examples - TEST_DIR=tests/em/fdem/forward - TEST_DIR=tests/em/fdem/inverse/derivs - TEST_DIR=tests/em/fdem/inverse/adjoint diff --git a/SimPEG/EM/Examples/__init__.py b/SimPEG/EM/Examples/__init__.py deleted file mode 100644 index eb36678d..00000000 --- a/SimPEG/EM/Examples/__init__.py +++ /dev/null @@ -1 +0,0 @@ -import CylInversion diff --git a/SimPEG/EM/Examples/CylInversion.py b/SimPEG/Examples/EM_FDEM_1D_Inversion.py similarity index 96% rename from SimPEG/EM/Examples/CylInversion.py rename to SimPEG/Examples/EM_FDEM_1D_Inversion.py index cfcfcfc1..fdf2750e 100644 --- a/SimPEG/EM/Examples/CylInversion.py +++ b/SimPEG/Examples/EM_FDEM_1D_Inversion.py @@ -4,6 +4,13 @@ from scipy.constants import mu_0 import matplotlib.pyplot as plt def run(plotIt=True): + """ + EM: FDEM: 1D: Inversion + ======================= + + Here we will create and run a FDEM 1D inversion. + + """ cs, ncx, ncz, npad = 5., 25, 15, 15 hx = [(cs,ncx), (cs,npad,1.3)] diff --git a/SimPEG/FLOW/Examples/Celia1990.py b/SimPEG/Examples/FLOW_Richards_1D_Celia1990.py similarity index 54% rename from SimPEG/FLOW/Examples/Celia1990.py rename to SimPEG/Examples/FLOW_Richards_1D_Celia1990.py index 24ae82a6..7c663e6b 100644 --- a/SimPEG/FLOW/Examples/Celia1990.py +++ b/SimPEG/Examples/FLOW_Richards_1D_Celia1990.py @@ -3,6 +3,39 @@ from SimPEG.FLOW import Richards import matplotlib.pyplot as plt def run(plotIt=True): + """ + FLOW: Richards: 1D: Celia1990 + ============================= + + There are two different forms of Richards equation that differ + on how they deal with the non-linearity in the time-stepping term. + + The most fundamental form, referred to as the + 'mixed'-form of Richards Equation Celia1990_ + + .. math:: + + \\frac{\partial \\theta(\psi)}{\partial t} - \\nabla \cdot k(\psi) \\nabla \psi - \\frac{\partial k(\psi)}{\partial z} = 0 + \quad \psi \in \Omega + + where \\\\(\\\\theta\\\\) is water content, and \\\\(\\\\psi\\\\) is pressure head. + This formulation of Richards equation is called the + 'mixed'-form because the equation is parameterized in \\\\(\\\\psi\\\\) + but the time-stepping is in terms of \\\\(\\\\theta\\\\). + + As noted in Celia1990_ the 'head'-based form of Richards + equation can be written in the continuous form as: + + .. math:: + + \\frac{\partial \\theta}{\partial \psi}\\frac{\partial \psi}{\partial t} - \\nabla \cdot k(\psi) \\nabla \psi - \\frac{\partial k(\psi)}{\partial z} = 0 \quad \psi \in \Omega + + However, it can be shown that this does not conserve mass in the discrete formulation. + + Here we reproduce the results from Celia1990_ demonstrating the head-based formulation and the mixed-formulation. + + .. _Celia1990: http://www.webpages.uidaho.edu/ch/papers/Celia.pdf + """ M = Mesh.TensorMesh([np.ones(40)]) M.setCellGradBC('dirichlet') params = Richards.Empirical.HaverkampParams().celia1990 @@ -47,6 +80,7 @@ def run(plotIt=True): plt.xlabel('Depth, cm') plt.ylabel('Pressure Head, cm') plt.legend(('$\Delta t$ = 10 sec','$\Delta t$ = 30 sec','$\Delta t$ = 120 sec')) + plt.show() if __name__ == '__main__': run() diff --git a/SimPEG/Examples/Forward_BasicDirectCurrent.py b/SimPEG/Examples/Forward_BasicDirectCurrent.py index a3c9ff97..06c9e79e 100644 --- a/SimPEG/Examples/Forward_BasicDirectCurrent.py +++ b/SimPEG/Examples/Forward_BasicDirectCurrent.py @@ -73,5 +73,4 @@ def run(plotIt=True): if __name__ == '__main__': - Utils._makeExample(__file__) run() diff --git a/SimPEG/Examples/Inversion_Linear.py b/SimPEG/Examples/Inversion_Linear.py index 2446bd58..a8a0eddc 100644 --- a/SimPEG/Examples/Inversion_Linear.py +++ b/SimPEG/Examples/Inversion_Linear.py @@ -1,29 +1,37 @@ from SimPEG import * -class LinearSurvey(Survey.BaseSurvey): - def projectFields(self, u): - return u - -class LinearProblem(Problem.BaseProblem): - """docstring for LinearProblem""" - - surveyPair = LinearSurvey - - def __init__(self, mesh, G, **kwargs): - Problem.BaseProblem.__init__(self, mesh, **kwargs) - self.G = G - - def fields(self, m, u=None): - return self.G.dot(m) - - def Jvec(self, m, v, u=None): - return self.G.dot(v) - - def Jtvec(self, m, v, u=None): - return self.G.T.dot(v) - def run(N=100, plotIt=True): + """ + Inversion: Linear Problem + ========================= + + Here we go over the basics of creating a linear problem and inversion. + + """ + + class LinearSurvey(Survey.BaseSurvey): + def projectFields(self, u): + return u + + class LinearProblem(Problem.BaseProblem): + + surveyPair = LinearSurvey + + def __init__(self, mesh, G, **kwargs): + Problem.BaseProblem.__init__(self, mesh, **kwargs) + self.G = G + + def fields(self, m, u=None): + return self.G.dot(m) + + def Jvec(self, m, v, u=None): + return self.G.dot(v) + + def Jtvec(self, m, v, u=None): + return self.G.T.dot(v) + + np.random.seed(1) mesh = Mesh.TensorMesh([N]) @@ -79,5 +87,4 @@ def run(N=100, plotIt=True): return prob, survey, mesh, mrec if __name__ == '__main__': - Utils._makeExample(__file__) run() diff --git a/SimPEG/Examples/Mesh_Basic_PlotImage.py b/SimPEG/Examples/Mesh_Basic_PlotImage.py new file mode 100644 index 00000000..3154f281 --- /dev/null +++ b/SimPEG/Examples/Mesh_Basic_PlotImage.py @@ -0,0 +1,46 @@ +from SimPEG import * + +def run(plotIt=True): + """ + Mesh: Basic: PlotImage + ====================== + + You can use M.PlotImage to plot images on all of the Meshes. + + + """ + M = Mesh.TensorMesh([32,32]) + v = Utils.ModelBuilder.randomModel(M.vnC, seed=789) + v = Utils.mkvc(v) + + O = Mesh.TreeMesh([32,32]) + O.refine(1) + def function(cell): + if (cell.center[0] < 0.75 and cell.center[0] > 0.25 and + cell.center[1] < 0.75 and cell.center[1] > 0.25):return 5 + if (cell.center[0] < 0.9 and cell.center[0] > 0.1 and + cell.center[1] < 0.9 and cell.center[1] > 0.1):return 4 + return 3 + O.refine(function) + + P = M.getInterpolationMat(O.gridCC, 'CC') + + ov = P * v + + if plotIt: + import matplotlib.pyplot as plt + + fig, axes = plt.subplots(1,2,figsize=(10,5)) + + out = M.plotImage(v, grid=True, ax=axes[0]) + cb = plt.colorbar(out[0], ax=axes[0]); cb.set_label("Random Field") + axes[0].set_title('TensorMesh') + + out = O.plotImage(ov, grid=True, ax=axes[1], clim=[0,1]) + cb = plt.colorbar(out[0], ax=axes[1]); cb.set_label("Random Field") + axes[1].set_title('TreeMesh') + + plt.show() + +if __name__ == '__main__': + run() diff --git a/SimPEG/Examples/Mesh_ThreeMeshes.py b/SimPEG/Examples/Mesh_Basic_Types.py similarity index 82% rename from SimPEG/Examples/Mesh_ThreeMeshes.py rename to SimPEG/Examples/Mesh_Basic_Types.py index 2fc7fa8d..430fe698 100644 --- a/SimPEG/Examples/Mesh_ThreeMeshes.py +++ b/SimPEG/Examples/Mesh_Basic_Types.py @@ -1,6 +1,13 @@ from SimPEG import * def run(plotIt=True): + """ + Mesh: Basic: Types + ================== + + Here we show SimPEG used to create three different types of meshes. + + """ sz = [16,16] tM = Mesh.TensorMesh(sz) qM = Mesh.TreeMesh(sz) @@ -20,5 +27,4 @@ def run(plotIt=True): plt.show() if __name__ == '__main__': - Utils._makeExample(__file__) run() diff --git a/SimPEG/Examples/Mesh_QuadTree_Create.py b/SimPEG/Examples/Mesh_QuadTree_Creation.py similarity index 50% rename from SimPEG/Examples/Mesh_QuadTree_Create.py rename to SimPEG/Examples/Mesh_QuadTree_Creation.py index f4417855..ede69a63 100644 --- a/SimPEG/Examples/Mesh_QuadTree_Create.py +++ b/SimPEG/Examples/Mesh_QuadTree_Creation.py @@ -1,7 +1,18 @@ from SimPEG import * def run(plotIt=True): - from SimPEG import Mesh, np + """ + Mesh: QuadTree: Creation + ======================== + + You can give the refine method a function, which is evaluated on every cell + of the TreeMesh. + + Occasionally it is useful to initially refine to a constant level + (e.g. 3 in this 32x32 mesh). This means the function is first evaluated + on an 8x8 mesh (2^3). + + """ M = Mesh.TreeMesh([32,32]) M.refine(3) def function(cell): @@ -14,5 +25,4 @@ def run(plotIt=True): if plotIt: M.plotGrid(showIt=True) if __name__ == '__main__': - Utils._makeExample(__file__) run() diff --git a/SimPEG/Examples/Mesh_QuadTree_HangingNodes.py b/SimPEG/Examples/Mesh_QuadTree_HangingNodes.py new file mode 100644 index 00000000..11726995 --- /dev/null +++ b/SimPEG/Examples/Mesh_QuadTree_HangingNodes.py @@ -0,0 +1,32 @@ +from SimPEG import * + +def run(plotIt=True): + """ + Mesh: QuadTree: Hanging Nodes + ============================= + + You can give the refine method a function, which is evaluated on every cell + of the TreeMesh. + + Occasionally it is useful to initially refine to a constant level + (e.g. 3 in this 32x32 mesh). This means the function is first evaluated + on an 8x8 mesh (2^3). + + """ + M = Mesh.TreeMesh([8,8]) + def function(cell): + xyz = cell.center + dist = ((xyz - [0.25,0.25])**2).sum()**0.5 + if dist < 0.25: + return 3 + return 2 + M.refine(function); + M.number() + if plotIt: + import matplotlib.pyplot as plt + M.plotGrid(nodes=True, cells=True, facesX=True) + plt.legend(('Grid', 'Cell Centers', 'Nodes', 'Hanging Nodes', 'X faces', 'Hanging X faces')) + plt.show() + +if __name__ == '__main__': + run() diff --git a/SimPEG/Examples/Mesh_Tensor_Creation.py b/SimPEG/Examples/Mesh_Tensor_Creation.py new file mode 100644 index 00000000..31ad3d69 --- /dev/null +++ b/SimPEG/Examples/Mesh_Tensor_Creation.py @@ -0,0 +1,35 @@ +from SimPEG import * + +def run(plotIt=True): + """ + + Mesh: Tensor: Creation + ====================== + + For tensor meshes, there are some functions that can come + in handy. For example, creating mesh tensors can be a bit time + consuming, these can be created speedily by just giving numbers + and sizes of padding. See the example below, that follows this + notation:: + + h1 = ( + (cellSize, numPad, [, increaseFactor]), + (cellSize, numCore), + (cellSize, numPad, [, increaseFactor]) + ) + + .. note:: + + You can center your mesh by passing a 'C' for the x0[i] position. + A 'N' will make the entire mesh negative, and a '0' (or a 0) will + make the mesh start at zero. + + """ + h1 = [(10, 5, -1.3), (5, 20), (10, 3, 1.3)] + M = Mesh.TensorMesh([h1, h1], x0='CN') + if plotIt: + M.plotGrid(showIt=True) + +if __name__ == '__main__': + run() + diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index 53b1f9a8..ac219a7f 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -5,5 +5,63 @@ __all__ = [] for x in glob(p.join(p.dirname(__file__), '*.py')): if not p.basename(x).startswith('__'): __import__(p.basename(x)[:-3], globals(), locals()) - __all__ += [p.basename(x)] + __all__ += [p.basename(x)[:-3]] del glob, p, x + +if __name__ == '__main__': + """ + + Run the following to create the examples documentation. + + """ + + import shutil, os + from SimPEG import Examples + + def _makeExample(filePath, runFunction): + filePath = os.path.realpath(filePath) + name = filePath.split(os.path.sep)[-1].rstrip('.pyc').rstrip('.py') + + docstr = runFunction.__doc__ + if docstr is None: + doc = '%s\n%s'%(name.replace('_',' '),'='*len(name)) + else: + doc = '\n'.join([_[8:].rstrip() for _ in docstr.split('\n')]) + + out = """.. _examples_%s: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + +%s + +.. plot:: + + from SimPEG import Examples + Examples.%s.run() + +.. literalinclude:: ../../SimPEG/Examples/%s.py + :language: python + :linenos: +"""%(name,doc,name,name) + + rst = os.path.sep.join((filePath.split(os.path.sep)[:-3] + ['docs', 'examples', name + '.rst'])) + + f = open(rst, 'w') + f.write(out) + f.close() + + + docExamplesDir = os.path.sep.join(os.path.realpath(__file__).split(os.path.sep)[:-3] + ['docs', 'examples']) + shutil.rmtree(docExamplesDir) + os.makedirs(docExamplesDir) + + for ex in dir(Examples): + if ex.startswith('_'): continue + E = getattr(Examples,ex) + _makeExample(E.__file__, E.run) diff --git a/SimPEG/FLOW/Examples/__init__.py b/SimPEG/FLOW/Examples/__init__.py deleted file mode 100644 index 7a894e11..00000000 --- a/SimPEG/FLOW/Examples/__init__.py +++ /dev/null @@ -1 +0,0 @@ -import Celia1990 diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 69a44fdc..263909e4 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -1975,24 +1975,28 @@ class TreeMesh(BaseTensorMesh, InnerProducts): fig = ax.figure if grid: + X, Y, Z = [], [], [] for ind in self._sortedCells: p = self._asPointer(ind) n = self._cellN(p) h = self._cellH(p) - x = [n[0] , n[0] + h[0], n[0] + h[0], n[0] , n[0]] - y = [n[1] , n[1] , n[1] + h[1], n[1] + h[1], n[1]] if self.dim == 2: - ax.plot(x,y, 'b-') + X += [n[0] , n[0] + h[0], n[0] + h[0], n[0] , n[0], np.nan] + Y += [n[1] , n[1] , n[1] + h[1], n[1] + h[1], n[1], np.nan] elif self.dim == 3: - ax.plot(x,y, 'b-', zs=[n[2]]*5) - z = [n[2] + h[2], n[2] + h[2], n[2] + h[2], n[2] + h[2], n[2] + h[2]] - ax.plot(x,y, 'b-', zs=z) + X += [n[0] , n[0] + h[0], n[0] + h[0], n[0] , n[0], np.nan]*2 + Y += [n[1] , n[1] , n[1] + h[1], n[1] + h[1], n[1], np.nan]*2 + Z += [n[2]]*5+[np.nan] + Z += [n[2] + h[2], n[2] + h[2], n[2] + h[2], n[2] + h[2], n[2] + h[2], np.nan] sides = [0,0], [h[0],0], [0,h[1]], [h[0],h[1]] for s in sides: - x = [n[0] + s[0], n[0] + s[0]] - y = [n[1] + s[1], n[1] + s[1]] - z = [n[2] , n[2] + h[2]] - ax.plot(x,y, 'b-', zs=z) + X += [n[0] + s[0], n[0] + s[0]] + Y += [n[1] + s[1], n[1] + s[1]] + Z += [n[2] , n[2] + h[2]] + if self.dim == 2: + ax.plot(X,Y, 'b-') + elif self.dim == 3: + ax.plot(X,Y, 'b-', zs=Z) if self.dim == 2: if cells: @@ -2004,11 +2008,11 @@ class TreeMesh(BaseTensorMesh, InnerProducts): ax.plot(self._gridN[:,0], self._gridN[:,1], 'ms') ax.plot(self._gridN[self._hangingN.keys(),0], self._gridN[self._hangingN.keys(),1], 'ms', ms=10, mfc='none', mec='m') if facesX: - ax.plot(self._gridFx[self._hangingFx.keys(),0], self._gridFx[self._hangingFx.keys(),1], 'gs', ms=10, mfc='none', mec='g') ax.plot(self._gridFx[:,0], self._gridFx[:,1], 'g>') + ax.plot(self._gridFx[self._hangingFx.keys(),0], self._gridFx[self._hangingFx.keys(),1], 'gs', ms=10, mfc='none', mec='g') if facesY: - ax.plot(self._gridFy[self._hangingFy.keys(),0], self._gridFy[self._hangingFy.keys(),1], 'gs', ms=10, mfc='none', mec='g') ax.plot(self._gridFy[:,0], self._gridFy[:,1], 'g^') + ax.plot(self._gridFy[self._hangingFy.keys(),0], self._gridFy[self._hangingFy.keys(),1], 'gs', ms=10, mfc='none', mec='g') ax.set_xlabel('x1') ax.set_ylabel('x2') elif self.dim == 3: @@ -2079,12 +2083,15 @@ class TreeMesh(BaseTensorMesh, InnerProducts): ax.grid(True) if showIt:plt.show() - def plotImage(self, I, ax=None, showIt=True, grid=False): + def plotImage(self, I, ax=None, showIt=False, grid=False, clim=None): if self.dim == 3: raise Exception('Use plot slice?') if ax is None: ax = plt.subplot(111) jet = cm = plt.get_cmap('jet') - cNorm = colors.Normalize(vmin=I.min(), vmax=I.max()) + cNorm = colors.Normalize( + vmin=I.min() if clim is None else clim[0], + vmax=I.max() if clim is None else clim[1]) + scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet) ax.set_xlim((self.x0[0], self.h[0].sum())) ax.set_ylim((self.x0[1], self.h[1].sum())) @@ -2093,8 +2100,10 @@ class TreeMesh(BaseTensorMesh, InnerProducts): ax.add_patch(plt.Rectangle((x0[0], x0[1]), sz[0], sz[1], facecolor=scalarMap.to_rgba(I[ii]), edgecolor='k' if grid else 'none')) # if text: ax.text(self.center[0],self.center[1],self.num) scalarMap._A = [] # http://stackoverflow.com/questions/8342549/matplotlib-add-colorbar-to-a-sequence-of-line-plots - plt.colorbar(scalarMap) + ax.set_xlabel('x') + ax.set_ylabel('y') if showIt: plt.show() + return [scalarMap] def plotSlice(self, v, vType='CC', normal='Z', ind=None, grid=True, view='real', diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index 67e1b117..5280ae79 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -1,6 +1,5 @@ from matutils import * from codeutils import * -from codeutils import _makeExample from meshutils import exampleLrmGrid, meshTensor, closestPoints, readUBCTensorMesh, writeUBCTensorMesh, writeUBCTensorModel, readVTRFile, writeVTRFile from curvutils import volTetra, faceInfo, indexCube from interputils import interpmat diff --git a/SimPEG/Utils/codeutils.py b/SimPEG/Utils/codeutils.py index fef34282..4a9a28a7 100644 --- a/SimPEG/Utils/codeutils.py +++ b/SimPEG/Utils/codeutils.py @@ -227,35 +227,3 @@ def requires(var): return requiresVarWrapper return requiresVar - -def _makeExample(filePath): - - import os - name = filePath.split(os.path.sep)[-1][:-3] - out = """.. _examples_%s: - -.. ------------------------------ .. -.. THIS FILE IS AUTO GENEREATED .. -.. ------------------------------ .. - -%s -%s - -.. plot:: - - from SimPEG import Examples - Examples.%s.run() - -.. literalinclude:: ../../SimPEG/Examples/%s.py - :language: python - :linenos: -"""%(name,name.replace('_',' '),'='*len(name),name,name) - - rst = os.path.sep.join((filePath.split(os.path.sep)[:-3] + ['docs', 'examples', name + '.rst'])) - - f = open(rst, 'w') - f.write(out) - f.close() - - - diff --git a/docs/examples/EM_FDEM_1D_Inversion.rst b/docs/examples/EM_FDEM_1D_Inversion.rst new file mode 100644 index 00000000..acbc8cdc --- /dev/null +++ b/docs/examples/EM_FDEM_1D_Inversion.rst @@ -0,0 +1,26 @@ +.. _examples_EM_FDEM_1D_Inversion: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + +EM: FDEM: 1D: Inversion +======================= + +Here we will create and run a FDEM 1D inversion. + + + +.. plot:: + + from SimPEG import Examples + Examples.EM_FDEM_1D_Inversion.run() + +.. literalinclude:: ../../SimPEG/Examples/EM_FDEM_1D_Inversion.py + :language: python + :linenos: diff --git a/docs/examples/FLOW_Richards_1D_Celia1990.rst b/docs/examples/FLOW_Richards_1D_Celia1990.rst new file mode 100644 index 00000000..d2e01c13 --- /dev/null +++ b/docs/examples/FLOW_Richards_1D_Celia1990.rst @@ -0,0 +1,52 @@ +.. _examples_FLOW_Richards_1D_Celia1990: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + +FLOW: Richards: 1D: Celia1990 +============================= + +There are two different forms of Richards equation that differ +on how they deal with the non-linearity in the time-stepping term. + +The most fundamental form, referred to as the +'mixed'-form of Richards Equation Celia1990_ + +.. math:: + + \frac{\partial \theta(\psi)}{\partial t} - \nabla \cdot k(\psi) \nabla \psi - \frac{\partial k(\psi)}{\partial z} = 0 + \quad \psi \in \Omega + +where \\(\\theta\\) is water content, and \\(\\psi\\) is pressure head. +This formulation of Richards equation is called the +'mixed'-form because the equation is parameterized in \\(\\psi\\) +but the time-stepping is in terms of \\(\\theta\\). + +As noted in Celia1990_ the 'head'-based form of Richards +equation can be written in the continuous form as: + +.. math:: + + \frac{\partial \theta}{\partial \psi}\frac{\partial \psi}{\partial t} - \nabla \cdot k(\psi) \nabla \psi - \frac{\partial k(\psi)}{\partial z} = 0 \quad \psi \in \Omega + +However, it can be shown that this does not conserve mass in the discrete formulation. + +Here we reproduce the results from Celia1990_ demonstrating the head-based formulation and the mixed-formulation. + +.. _Celia1990: http://www.webpages.uidaho.edu/ch/papers/Celia.pdf + + +.. plot:: + + from SimPEG import Examples + Examples.FLOW_Richards_1D_Celia1990.run() + +.. literalinclude:: ../../SimPEG/Examples/FLOW_Richards_1D_Celia1990.py + :language: python + :linenos: diff --git a/docs/examples/Forward_BasicDirectCurrent.rst b/docs/examples/Forward_BasicDirectCurrent.rst index 6fc816e7..20b39eb8 100644 --- a/docs/examples/Forward_BasicDirectCurrent.rst +++ b/docs/examples/Forward_BasicDirectCurrent.rst @@ -1,8 +1,12 @@ .. _examples_Forward_BasicDirectCurrent: -.. ------------------------------ .. -.. THIS FILE IS AUTO GENEREATED .. -.. ------------------------------ .. +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. Forward BasicDirectCurrent ========================== diff --git a/docs/examples/Inversion_Linear.rst b/docs/examples/Inversion_Linear.rst index 637315ae..d635d8e1 100644 --- a/docs/examples/Inversion_Linear.rst +++ b/docs/examples/Inversion_Linear.rst @@ -1,11 +1,20 @@ .. _examples_Inversion_Linear: -.. ------------------------------ .. -.. THIS FILE IS AUTO GENEREATED .. -.. ------------------------------ .. +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + +Inversion: Linear Problem +========================= + +Here we go over the basics of creating a linear problem and inversion. + -Inversion Linear -================ .. plot:: diff --git a/docs/examples/Mesh_Basic_PlotImage.rst b/docs/examples/Mesh_Basic_PlotImage.rst new file mode 100644 index 00000000..a730f303 --- /dev/null +++ b/docs/examples/Mesh_Basic_PlotImage.rst @@ -0,0 +1,27 @@ +.. _examples_Mesh_Basic_PlotImage: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + +Mesh: Basic: PlotImage +====================== + +You can use M.PlotImage to plot images on all of the Meshes. + + + + +.. plot:: + + from SimPEG import Examples + Examples.Mesh_Basic_PlotImage.run() + +.. literalinclude:: ../../SimPEG/Examples/Mesh_Basic_PlotImage.py + :language: python + :linenos: diff --git a/docs/examples/Mesh_Basic_Types.rst b/docs/examples/Mesh_Basic_Types.rst new file mode 100644 index 00000000..9bbce0e8 --- /dev/null +++ b/docs/examples/Mesh_Basic_Types.rst @@ -0,0 +1,26 @@ +.. _examples_Mesh_Basic_Types: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + +Mesh: Basic: Types +================== + +Here we show SimPEG used to create three different types of meshes. + + + +.. plot:: + + from SimPEG import Examples + Examples.Mesh_Basic_Types.run() + +.. literalinclude:: ../../SimPEG/Examples/Mesh_Basic_Types.py + :language: python + :linenos: diff --git a/docs/examples/Mesh_QuadTree_Create.rst b/docs/examples/Mesh_QuadTree_Create.rst deleted file mode 100644 index 644593d5..00000000 --- a/docs/examples/Mesh_QuadTree_Create.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. _examples_Mesh_QuadTree_Create: - -.. ------------------------------ .. -.. THIS FILE IS AUTO GENEREATED .. -.. ------------------------------ .. - -Mesh QuadTree Create -==================== - -.. plot:: - - from SimPEG import Examples - Examples.Mesh_QuadTree_Create.run() - -.. literalinclude:: ../../SimPEG/Examples/Mesh_QuadTree_Create.py - :language: python - :linenos: diff --git a/docs/examples/Mesh_QuadTree_Creation.rst b/docs/examples/Mesh_QuadTree_Creation.rst new file mode 100644 index 00000000..5db5a982 --- /dev/null +++ b/docs/examples/Mesh_QuadTree_Creation.rst @@ -0,0 +1,31 @@ +.. _examples_Mesh_QuadTree_Creation: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + +Mesh: QuadTree: Creation +======================== + +You can give the refine method a function, which is evaluated on every cell +of the TreeMesh. + +Occasionally it is useful to initially refine to a constant level +(e.g. 3 in this 32x32 mesh). This means the function is first evaluated +on an 8x8 mesh (2^3). + + + +.. plot:: + + from SimPEG import Examples + Examples.Mesh_QuadTree_Creation.run() + +.. literalinclude:: ../../SimPEG/Examples/Mesh_QuadTree_Creation.py + :language: python + :linenos: diff --git a/docs/examples/Mesh_QuadTree_HangingNodes.rst b/docs/examples/Mesh_QuadTree_HangingNodes.rst new file mode 100644 index 00000000..93875478 --- /dev/null +++ b/docs/examples/Mesh_QuadTree_HangingNodes.rst @@ -0,0 +1,31 @@ +.. _examples_Mesh_QuadTree_HangingNodes: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + +Mesh: QuadTree: Hanging Nodes +============================= + +You can give the refine method a function, which is evaluated on every cell +of the TreeMesh. + +Occasionally it is useful to initially refine to a constant level +(e.g. 3 in this 32x32 mesh). This means the function is first evaluated +on an 8x8 mesh (2^3). + + + +.. plot:: + + from SimPEG import Examples + Examples.Mesh_QuadTree_HangingNodes.run() + +.. literalinclude:: ../../SimPEG/Examples/Mesh_QuadTree_HangingNodes.py + :language: python + :linenos: diff --git a/docs/examples/Mesh_Tensor_Creation.rst b/docs/examples/Mesh_Tensor_Creation.rst new file mode 100644 index 00000000..e6cc5b67 --- /dev/null +++ b/docs/examples/Mesh_Tensor_Creation.rst @@ -0,0 +1,43 @@ +.. _examples_Mesh_Tensor_Creation: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + + +Mesh: Tensor: Creation +====================== + +For tensor meshes, there are some functions that can come +in handy. For example, creating mesh tensors can be a bit time +consuming, these can be created speedily by just giving numbers +and sizes of padding. See the example below, that follows this +notation:: + + h1 = ( + (cellSize, numPad, [, increaseFactor]), + (cellSize, numCore), + (cellSize, numPad, [, increaseFactor]) + ) + +.. note:: + + You can center your mesh by passing a 'C' for the x0[i] position. + A 'N' will make the entire mesh negative, and a '0' (or a 0) will + make the mesh start at zero. + + + +.. plot:: + + from SimPEG import Examples + Examples.Mesh_Tensor_Creation.run() + +.. literalinclude:: ../../SimPEG/Examples/Mesh_Tensor_Creation.py + :language: python + :linenos: diff --git a/docs/examples/Mesh_ThreeMeshes.rst b/docs/examples/Mesh_ThreeMeshes.rst deleted file mode 100644 index 948398a7..00000000 --- a/docs/examples/Mesh_ThreeMeshes.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. _examples_Mesh_ThreeMeshes: - -.. ------------------------------ .. -.. THIS FILE IS AUTO GENEREATED .. -.. ------------------------------ .. - -Mesh ThreeMeshes -================ - -.. plot:: - - from SimPEG import Examples - Examples.Mesh_ThreeMeshes.run() - -.. literalinclude:: ../../SimPEG/Examples/Mesh_ThreeMeshes.py - :language: python - :linenos: diff --git a/tests/em/examples/__init__.py b/tests/em/examples/__init__.py deleted file mode 100644 index 38d84328..00000000 --- a/tests/em/examples/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -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) diff --git a/tests/em/examples/test_Examples.py b/tests/em/examples/test_Examples.py deleted file mode 100644 index 5a601d3b..00000000 --- a/tests/em/examples/test_Examples.py +++ /dev/null @@ -1,10 +0,0 @@ -import unittest, os -from SimPEG.EM import Examples - -class EM_ExamplesRunning(unittest.TestCase): - - def test_CylInversion(self): - Examples.CylInversion.run(plotIt=False) - -if __name__ == '__main__': - unittest.main() diff --git a/tests/flow/test_examples.py b/tests/flow/test_examples.py deleted file mode 100644 index bc519e6d..00000000 --- a/tests/flow/test_examples.py +++ /dev/null @@ -1,12 +0,0 @@ -import unittest -import sys -from SimPEG.FLOW.Examples import Celia1990 -import numpy as np - -class TestCelia1990(unittest.TestCase): - def test_running(self): - Celia1990.run(plotIt=False) - self.assertTrue(True) - -if __name__ == '__main__': - unittest.main() From b2aab4163b655b93c1465012b9e5e2024e308e05 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Thu, 26 Nov 2015 13:56:04 -0700 Subject: [PATCH 05/19] New examples for Mesh --- .../Examples/Mesh_Operators_CahnHilliard.py | 105 ++++++++++++++++++ SimPEG/Examples/Mesh_QuadTree_FaceDiv.py | 49 ++++++++ docs/examples/Mesh_Operators_CahnHilliard.rst | 57 ++++++++++ docs/examples/Mesh_QuadTree_FaceDiv.rst | 26 +++++ 4 files changed, 237 insertions(+) create mode 100644 SimPEG/Examples/Mesh_Operators_CahnHilliard.py create mode 100644 SimPEG/Examples/Mesh_QuadTree_FaceDiv.py create mode 100644 docs/examples/Mesh_Operators_CahnHilliard.rst create mode 100644 docs/examples/Mesh_QuadTree_FaceDiv.rst diff --git a/SimPEG/Examples/Mesh_Operators_CahnHilliard.py b/SimPEG/Examples/Mesh_Operators_CahnHilliard.py new file mode 100644 index 00000000..8e42e617 --- /dev/null +++ b/SimPEG/Examples/Mesh_Operators_CahnHilliard.py @@ -0,0 +1,105 @@ +from SimPEG import * + +def run(plotIt=True, n=60): + """ + Mesh: Operators: Cahn Hilliard + ============================== + + This example is based on the example in the FiPy_ library. + Please see their documentation for more information about the Cahn-Hilliard equation. + + The "Cahn-Hilliard" equation separates a field \\\\( \\\\phi \\\\) into 0 and 1 with smooth transitions. + + .. math:: + + \\frac{\partial \phi}{\partial t} = \\nabla \cdot D \\nabla \left( \\frac{\partial f}{\partial \phi} - \epsilon^2 \\nabla^2 \phi \\right) + + Where \\\\( f \\\\) is the energy function \\\\( f = ( a^2 / 2 )\\\\phi^2(1 - \\\\phi)^2 \\\\) + which drives \\\\( \\\\phi \\\\) towards either 0 or 1, this competes with the term + \\\\(\\\\epsilon^2 \\\\nabla^2 \\\\phi \\\\) which is a diffusion term that creates smooth changes in \\\\( \\\\phi \\\\). + The equation can be factored: + + .. math:: + + \\frac{\partial \phi}{\partial t} = \\nabla \cdot D \\nabla \psi \\\\ + \psi = \\frac{\partial^2 f}{\partial \phi^2} (\phi - \phi^{\\text{old}}) + \\frac{\partial f}{\partial \phi} - \epsilon^2 \\nabla^2 \phi + + Here we will need the derivatives of \\\\( f \\\\): + + .. math:: + + \\frac{\partial f}{\partial \phi} = (a^2/2)2\phi(1-\phi)(1-2\phi) + \\frac{\partial^2 f}{\partial \phi^2} = (a^2/2)2[1-6\phi(1-\phi)] + + The implementation below uses backwards Euler in time with an exponentially increasing time step. + The initial \\\\( \\\\phi \\\\) is a normally distributed field with a standard deviation of 0.1 and mean of 0.5. + The grid is 60x60 and takes a few seconds to solve ~130 times. The results are seen below, and you can see the + field separating as the time increases. + + .. _FiPy: http://www.ctcms.nist.gov/fipy/examples/cahnHilliard/generated/examples.cahnHilliard.mesh2DCoupled.html + + """ + + np.random.seed(5) + + # Here we are going to rearrange the equations: + + # (phi_ - phi)/dt = A*(d2fdphi2*(phi_ - phi) + dfdphi - L*phi_) + # (phi_ - phi)/dt = A*(d2fdphi2*phi_ - d2fdphi2*phi + dfdphi - L*phi_) + # (phi_ - phi)/dt = A*d2fdphi2*phi_ + A*( - d2fdphi2*phi + dfdphi - L*phi_) + # phi_ - phi = dt*A*d2fdphi2*phi_ + dt*A*(- d2fdphi2*phi + dfdphi - L*phi_) + # phi_ - dt*A*d2fdphi2 * phi_ = dt*A*(- d2fdphi2*phi + dfdphi - L*phi_) + phi + # (I - dt*A*d2fdphi2) * phi_ = dt*A*(- d2fdphi2*phi + dfdphi - L*phi_) + phi + # (I - dt*A*d2fdphi2) * phi_ = dt*A*dfdphi - dt*A*d2fdphi2*phi - dt*A*L*phi_ + phi + # (dt*A*d2fdphi2 - I) * phi_ = dt*A*d2fdphi2*phi + dt*A*L*phi_ - phi - dt*A*dfdphi + # (dt*A*d2fdphi2 - I - dt*A*L) * phi_ = (dt*A*d2fdphi2 - I)*phi - dt*A*dfdphi + + h = [(0.25,n)] + M = Mesh.TensorMesh([h,h]) + + # Constants + D = a = epsilon = 1. + I = Utils.speye(M.nC) + + # Operators + A = D * M.faceDiv * M.cellGrad + L = epsilon**2 * M.faceDiv * M.cellGrad + + duration = 75 + elapsed = 0. + dexp = -5 + phi = np.random.normal(loc=0.5,scale=0.01,size=M.nC) + ii, jj = 0, 0 + PHIS = [] + capture = np.logspace(-1,np.log10(duration),8) + while elapsed < duration: + dt = min(100, np.exp(dexp)) + elapsed += dt + dexp += 0.05 + + dfdphi = a**2 * 2 * phi * (1 - phi) * (1 - 2 * phi) + d2fdphi2 = Utils.sdiag(a**2 * 2 * (1 - 6 * phi * (1 - phi))) + + MAT = (dt*A*d2fdphi2 - I - dt*A*L) + rhs = (dt*A*d2fdphi2 - I)*phi - dt*A*dfdphi + phi = Solver(MAT)*rhs + + if elapsed > capture[jj]: + PHIS += [(elapsed, phi.copy())] + jj += 1 + if ii % 10 == 0: print ii, elapsed + ii += 1 + + if plotIt: + import matplotlib.pyplot as plt + fig, axes = plt.subplots(2,4,figsize=(14,6)) + axes = np.array(axes).flatten().tolist() + for ii, ax in zip(np.linspace(0,len(PHIS)-1,len(axes)),axes): + ii = int(ii) + out = M.plotImage(PHIS[ii][1],ax=ax) + ax.axis('off') + ax.set_title('Elapsed Time: %4.1f'%PHIS[ii][0]) + plt.show() + +if __name__ == '__main__': + run() diff --git a/SimPEG/Examples/Mesh_QuadTree_FaceDiv.py b/SimPEG/Examples/Mesh_QuadTree_FaceDiv.py new file mode 100644 index 00000000..5bd67929 --- /dev/null +++ b/SimPEG/Examples/Mesh_QuadTree_FaceDiv.py @@ -0,0 +1,49 @@ +from SimPEG import * + +def run(plotIt=True, n=60): + """ + Mesh: QuadTree: FaceDiv + ======================= + + + + """ + + + M = Mesh.TreeMesh([[(1,16)],[(1,16)]], levels=4) + M._refineCell([0,0,0]) + M._refineCell([0,0,1]) + M._refineCell([4,4,2]) + M.__dirty__ = True + M.number() + + + if plotIt: + import matplotlib.pyplot as plt + fig, axes = plt.subplots(2,1,figsize=(10,10)) + + M.plotGrid(cells=True, nodes=False, ax=axes[0]) + axes[0].axis('off') + axes[0].set_title('Simple QuadTree Mesh') + axes[0].set_xlim([-1,17]) + axes[0].set_ylim([-1,17]) + + for ii, loc in zip(range(M.nC),M.gridCC): + axes[0].text(loc[0]+0.2,loc[1],'%d'%ii, color='r') + + axes[0].plot(M.gridFx[:,0],M.gridFx[:,1], 'g>') + for ii, loc in zip(range(M.nFx),M.gridFx): + axes[0].text(loc[0]+0.2,loc[1],'%d'%ii, color='g') + + axes[0].plot(M.gridFy[:,0],M.gridFy[:,1], 'm^') + for ii, loc in zip(range(M.nFy),M.gridFy): + axes[0].text(loc[0]+0.2,loc[1]+0.2,'%d'%(ii+M.nFx), color='m') + + axes[1].spy(M.faceDiv) + axes[1].set_title('Face Divergence') + axes[1].set_ylabel('Cell Number') + axes[1].set_xlabel('Face Number') + plt.show() + +if __name__ == '__main__': + run() diff --git a/docs/examples/Mesh_Operators_CahnHilliard.rst b/docs/examples/Mesh_Operators_CahnHilliard.rst new file mode 100644 index 00000000..9786e911 --- /dev/null +++ b/docs/examples/Mesh_Operators_CahnHilliard.rst @@ -0,0 +1,57 @@ +.. _examples_Mesh_Operators_CahnHilliard: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + +Mesh: Operators: Cahn Hilliard +============================== + +This example is based on the example in the FiPy_ library. +Please see their documentation for more information about the Cahn-Hilliard equation. + +The "Cahn-Hilliard" equation separates a field \\( \\phi \\) into 0 and 1 with smooth transitions. + +.. math:: + + \frac{\partial \phi}{\partial t} = \nabla \cdot D \nabla \left( \frac{\partial f}{\partial \phi} - \epsilon^2 \nabla^2 \phi \right) + +Where \\( f \\) is the energy function \\( f = ( a^2 / 2 )\\phi^2(1 - \\phi)^2 \\) +which drives \\( \\phi \\) towards either 0 or 1, this competes with the term +\\(\\epsilon^2 \\nabla^2 \\phi \\) which is a diffusion term that creates smooth changes in \\( \\phi \\). +The equation can be factored: + +.. math:: + + \frac{\partial \phi}{\partial t} = \nabla \cdot D \nabla \psi \\ + \psi = \frac{\partial^2 f}{\partial \phi^2} (\phi - \phi^{\text{old}}) + \frac{\partial f}{\partial \phi} - \epsilon^2 \nabla^2 \phi + +Here we will need the derivatives of \\( f \\): + +.. math:: + + \frac{\partial f}{\partial \phi} = (a^2/2)2\phi(1-\phi)(1-2\phi) + \frac{\partial^2 f}{\partial \phi^2} = (a^2/2)2[1-6\phi(1-\phi)] + +The implementation below uses backwards Euler in time with an exponentially increasing time step. +The initial \\( \\phi \\) is a normally distributed field with a standard deviation of 0.1 and mean of 0.5. +The grid is 60x60 and takes a few seconds to solve ~130 times. The results are seen below, and you can see the +field separating as the time increases. + +.. _FiPy: http://www.ctcms.nist.gov/fipy/examples/cahnHilliard/generated/examples.cahnHilliard.mesh2DCoupled.html + + + +.. plot:: + + from SimPEG import Examples + Examples.Mesh_Operators_CahnHilliard.run() + +.. literalinclude:: ../../SimPEG/Examples/Mesh_Operators_CahnHilliard.py + :language: python + :linenos: diff --git a/docs/examples/Mesh_QuadTree_FaceDiv.rst b/docs/examples/Mesh_QuadTree_FaceDiv.rst new file mode 100644 index 00000000..6bfdd47f --- /dev/null +++ b/docs/examples/Mesh_QuadTree_FaceDiv.rst @@ -0,0 +1,26 @@ +.. _examples_Mesh_QuadTree_FaceDiv: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + +Mesh: QuadTree: FaceDiv +======================= + + + + + +.. plot:: + + from SimPEG import Examples + Examples.Mesh_QuadTree_FaceDiv.run() + +.. literalinclude:: ../../SimPEG/Examples/Mesh_QuadTree_FaceDiv.py + :language: python + :linenos: From 528253a8cbaaf5e5cda8d3b73c4dea86676701fd Mon Sep 17 00:00:00 2001 From: Brendan Smithyman Date: Thu, 26 Nov 2015 19:18:04 -0500 Subject: [PATCH 06/19] Generalize mapPair --- SimPEG/Regularization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index e3506290..65fba9f3 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -24,7 +24,7 @@ class BaseRegularization(object): Utils.setKwargs(self, **kwargs) self.mesh = mesh assert isinstance(mesh, Mesh.BaseMesh), "mesh must be a SimPEG.Mesh object." - self.mapping = mapping or Maps.IdentityMap(mesh) + self.mapping = mapping or self.mapPair(mesh) self.mapping._assertMatchesPair(self.mapPair) @property From f0f3f6c06a0640bc5ded5359b6f5424404e1421d Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Sat, 2 Jan 2016 18:06:49 -0800 Subject: [PATCH 07/19] Update the examples init.py to explicitly reference things. You can run the main function to update the docs and imports. --- SimPEG/Examples/__init__.py | 62 ++++++++++++++++++++++++++++--------- docs/api_Tests.rst | 2 +- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index ac219a7f..191664bb 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -1,24 +1,60 @@ -# This will import everything in the directory into this file -from os import path as p -from glob import glob -__all__ = [] -for x in glob(p.join(p.dirname(__file__), '*.py')): - if not p.basename(x).startswith('__'): - __import__(p.basename(x)[:-3], globals(), locals()) - __all__ += [p.basename(x)[:-3]] -del glob, p, x +# Run this file to add imports. + +##### AUTOIMPORTS ##### +import EM_FDEM_1D_Inversion +import FLOW_Richards_1D_Celia1990 +import Forward_BasicDirectCurrent +import Inversion_Linear +import Mesh_Basic_PlotImage +import Mesh_Basic_Types +import Mesh_Operators_CahnHilliard +import Mesh_QuadTree_Creation +import Mesh_QuadTree_FaceDiv +import Mesh_QuadTree_HangingNodes +import Mesh_Tensor_Creation +##### AUTOIMPORTS ##### if __name__ == '__main__': """ - Run the following to create the examples documentation. + Run the following to create the examples documentation and add to the imports at the top. """ import shutil, os from SimPEG import Examples + # Create the examples dir in the docs folder. + docExamplesDir = os.path.sep.join(os.path.realpath(__file__).split(os.path.sep)[:-3] + ['docs', 'examples']) + shutil.rmtree(docExamplesDir) + os.makedirs(docExamplesDir) + + # Get all the python examples in this folder + thispath = os.path.sep.join(__file__.split(os.path.sep)[:-1]) + onlyfiles = [f[:-3] for f in os.listdir(thispath) if os.path.isfile(os.path.join(thispath, f)) and f.endswith('.py') and not f.startswith('_')] + + # Add the imports to the top in the AUTOIMPORTS section + f = file(__file__, 'r') + inimports = False + out = '' + for line in f: + if not inimports: + out += line + + if line == "##### AUTOIMPORTS #####\n": + inimports = not inimports + if inimports: + out += '\n'.join(["import %s"%_ for _ in onlyfiles]) + out += '\n##### AUTOIMPORTS #####\n' + f.close() + + f = file(__file__, 'w') + f.write(out) + f.close() + + def _makeExample(filePath, runFunction): + """Makes the example given a path of the file and the run function.""" filePath = os.path.realpath(filePath) name = filePath.split(os.path.sep)[-1].rstrip('.pyc').rstrip('.py') @@ -52,15 +88,11 @@ if __name__ == '__main__': rst = os.path.sep.join((filePath.split(os.path.sep)[:-3] + ['docs', 'examples', name + '.rst'])) + print 'Creating: %s.rst'%name f = open(rst, 'w') f.write(out) f.close() - - docExamplesDir = os.path.sep.join(os.path.realpath(__file__).split(os.path.sep)[:-3] + ['docs', 'examples']) - shutil.rmtree(docExamplesDir) - os.makedirs(docExamplesDir) - for ex in dir(Examples): if ex.startswith('_'): continue E = getattr(Examples,ex) diff --git a/docs/api_Tests.rst b/docs/api_Tests.rst index 614d8747..b0b2fbd0 100644 --- a/docs/api_Tests.rst +++ b/docs/api_Tests.rst @@ -3,6 +3,6 @@ Testing SimPEG ============== -.. automodule:: SimPEG.Tests.TestUtils +.. automodule:: SimPEG.Tests :members: :undoc-members: From a18d48348d83b800115ff0a00cd2e8559a1b128a Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Sat, 2 Jan 2016 18:20:58 -0800 Subject: [PATCH 08/19] Merge fast tests on travis. --- .travis.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index b9826bab..8c8637af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,15 +5,13 @@ python: sudo: false env: + - TEST_DIR="tests/mesh tests/base tests/utils" + - TEST_DIR=tests/examples - TEST_DIR=tests/em/fdem/forward - TEST_DIR=tests/em/fdem/inverse/derivs - TEST_DIR=tests/em/fdem/inverse/adjoint - TEST_DIR=tests/em/tdem - - TEST_DIR=tests/mesh - TEST_DIR=tests/flow - - TEST_DIR=tests/utils - - TEST_DIR=tests/base - - TEST_DIR=tests/examples # Setup anaconda before_install: From d64fd4ae3558ae1771aa342ed1a8460184b2cd00 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Sat, 2 Jan 2016 18:29:04 -0800 Subject: [PATCH 09/19] List examples in the init file. --- SimPEG/Examples/__init__.py | 10 +++++++--- tests/examples/test_examples.py | 4 +--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index 191664bb..8431e4ba 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -12,6 +12,9 @@ import Mesh_QuadTree_Creation import Mesh_QuadTree_FaceDiv import Mesh_QuadTree_HangingNodes import Mesh_Tensor_Creation + +__examples__ = ["EM_FDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation"] + ##### AUTOIMPORTS ##### if __name__ == '__main__': @@ -30,8 +33,8 @@ if __name__ == '__main__': os.makedirs(docExamplesDir) # Get all the python examples in this folder - thispath = os.path.sep.join(__file__.split(os.path.sep)[:-1]) - onlyfiles = [f[:-3] for f in os.listdir(thispath) if os.path.isfile(os.path.join(thispath, f)) and f.endswith('.py') and not f.startswith('_')] + thispath = os.path.sep.join(__file__.split(os.path.sep)[:-1]) + exfiles = [f[:-3] for f in os.listdir(thispath) if os.path.isfile(os.path.join(thispath, f)) and f.endswith('.py') and not f.startswith('_')] # Add the imports to the top in the AUTOIMPORTS section f = file(__file__, 'r') @@ -44,7 +47,8 @@ if __name__ == '__main__': if line == "##### AUTOIMPORTS #####\n": inimports = not inimports if inimports: - out += '\n'.join(["import %s"%_ for _ in onlyfiles]) + out += '\n'.join(["import %s"%_ for _ in exfiles]) + out += '\n\n__examples__ = ["' + '", "'.join(exfiles)+ '"]\n' out += '\n##### AUTOIMPORTS #####\n' f.close() diff --git a/tests/examples/test_examples.py b/tests/examples/test_examples.py index 48cbaa65..cffa2094 100644 --- a/tests/examples/test_examples.py +++ b/tests/examples/test_examples.py @@ -10,10 +10,8 @@ def get(test): self.assertTrue(True) return func attrs = dict() -tests = [_ for _ in dir(Examples) if not _.startswith('_')] -for test in tests: +for test in Examples.__examples__: attrs['test_'+test] = get(test) -del get, tests, _ TestExamples = type('TestExamples', (unittest.TestCase,), attrs) From dd5f5df69eefb8ed106376c73a37b0466fa3adfd Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Sun, 3 Jan 2016 12:48:01 -0800 Subject: [PATCH 10/19] my_function.__name__ must be set to 'test_' for nosetests --- tests/examples/test_examples.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/examples/test_examples.py b/tests/examples/test_examples.py index cffa2094..2e4803b1 100644 --- a/tests/examples/test_examples.py +++ b/tests/examples/test_examples.py @@ -4,11 +4,11 @@ from SimPEG import Examples import numpy as np def get(test): - def func(self): + def test_func(self): print '\nTesting %s.run(plotIt=False)\n'%test getattr(Examples, test).run(plotIt=False) self.assertTrue(True) - return func + return test_func attrs = dict() for test in Examples.__examples__: attrs['test_'+test] = get(test) From 9ebd0fcedc0aa830dcbad483d67d252ed543bf2d Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Sun, 3 Jan 2016 19:02:06 -0800 Subject: [PATCH 11/19] Use pymatsolver in TravisCI --- .travis.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8c8637af..db79b031 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,16 @@ python: sudo: false +addons: + apt: + packages: + - gcc + - gfortran + - libopenmpi-dev + - libmumps-seq-dev + - libblas-dev + - liblapack-dev + env: - TEST_DIR="tests/mesh tests/base tests/utils" - TEST_DIR=tests/examples @@ -23,9 +33,12 @@ before_install: # Install packages install: - - conda install --yes pip python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib cython ipython + - conda install --yes pip python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib cython ipython nose - pip install nose-cov python-coveralls - # - pip install -r requirements.txt + + - git clone https://github.com/rowanc1/pymatsolver.git + - cd pymatsolver; python setup.py install; cd .. + - python setup.py install - python setup.py build_ext --inplace From 00a29d27aa6f1bb0815342a5e3d4cf862db34d36 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Sun, 3 Jan 2016 19:11:45 -0800 Subject: [PATCH 12/19] Decrease the number of iterations on the EM derivatives. This is to increase the speed at which travis runs tests. --- tests/em/fdem/inverse/derivs/test_FDEM_derivs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/em/fdem/inverse/derivs/test_FDEM_derivs.py b/tests/em/fdem/inverse/derivs/test_FDEM_derivs.py index 52108c4e..d3bcb218 100644 --- a/tests/em/fdem/inverse/derivs/test_FDEM_derivs.py +++ b/tests/em/fdem/inverse/derivs/test_FDEM_derivs.py @@ -38,7 +38,7 @@ def derivTest(fdemType, comp): survey = prb.survey def fun(x): return survey.dpred(x), lambda x: prb.Jvec(x0, x) - return Tests.checkDerivative(fun, x0, num=3, plotIt=False, eps=FLR) + return Tests.checkDerivative(fun, x0, num=2, plotIt=False, eps=FLR) class FDEM_DerivTests(unittest.TestCase): From d93a23306ce222eee6c3caab58ba08979e5b4154 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Sun, 10 Jan 2016 12:47:43 -0800 Subject: [PATCH 13/19] =?UTF-8?q?Bump=20version:=200.1.3=20=E2=86=92=200.1?= =?UTF-8?q?.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- SimPEG/__init__.py | 2 +- docs/conf.py | 4 ++-- setup.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index f739d080..f5efbf0d 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 0.1.3 +current_version = 0.1.4 files = setup.py SimPEG/__init__.py docs/conf.py diff --git a/SimPEG/__init__.py b/SimPEG/__init__.py index 369134e7..94bf255f 100644 --- a/SimPEG/__init__.py +++ b/SimPEG/__init__.py @@ -15,7 +15,7 @@ import Directives import Inversion import Tests -__version__ = '0.1.3' +__version__ = '0.1.4' __author__ = 'Rowan Cockett' __license__ = 'MIT' __copyright__ = 'Copyright 2014 Rowan Cockett' diff --git a/docs/conf.py b/docs/conf.py index 3bb33621..4f3f4462 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -51,9 +51,9 @@ copyright = u'2013, SimPEG Developers' # built documents. # # The short X.Y version. -version = '0.1.3' +version = '0.1.4' # The full version, including alpha/beta/rc tags. -release = '0.1.3' +release = '0.1.4' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 531dc539..a90d6119 100644 --- a/setup.py +++ b/setup.py @@ -76,7 +76,7 @@ with open("README.rst") as f: setup( name = "SimPEG", - version = "0.1.3", + version = "0.1.4", packages = find_packages(), install_requires = ['numpy>=1.7', 'scipy>=0.13', From 8da717521cf95484c21812a94982c18d8c5356c8 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Sun, 10 Jan 2016 13:01:00 -0800 Subject: [PATCH 14/19] Update scripts for pip --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index a90d6119..34c29703 100644 --- a/setup.py +++ b/setup.py @@ -64,6 +64,7 @@ cython_files = [ "SimPEG/Mesh/TreeUtils" ] extensions = [Extension(f, [f+ext]) for f in cython_files] +scripts = [f+'.pyx' for f in cython_files] if USE_CYTHON and "cleanall" not in args: from Cython.Build import cythonize @@ -95,5 +96,6 @@ setup( use_2to3 = False, include_dirs=[np.get_include()], ext_modules = extensions, + scripts=scripts, **cythonKwargs ) From 985d5b6469f39d56aea9d5d94ccb1e59fc10dee0 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Sun, 10 Jan 2016 13:01:05 -0800 Subject: [PATCH 15/19] =?UTF-8?q?Bump=20version:=200.1.7=20=E2=86=92=200.1?= =?UTF-8?q?.8=20(+7=20squashed=20commits)=20Squashed=20commits:=20[ac5bb36?= =?UTF-8?q?]=20Bump=20version:=200.1.8=20=E2=86=92=200.1.9=20[8acd6b2]=20I?= =?UTF-8?q?mportException=20-->=20ImportError=20[ac410a8]=20matplotlib.pyp?= =?UTF-8?q?lot=20has=20errors=20on=20import,=20put=20these=20in=20the=20fu?= =?UTF-8?q?nctions=20that=20rely=20on=20them=20directly.=20[f128a20]=20Bum?= =?UTF-8?q?p=20version:=200.1.6=20=E2=86=92=200.1.7=20[5866bea]=20Remove?= =?UTF-8?q?=20IPython=20utils.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are out of date, and have problems on Linux (without a proper visual backend). [a519e56] Bump version: 0.1.5 → 0.1.6 [f45aa83] Bump version: 0.1.4 → 0.1.5 --- .bumpversion.cfg | 2 +- SimPEG/EM/Analytics/FDEM.py | 1 - SimPEG/Examples/EM_FDEM_1D_Inversion.py | 5 +- SimPEG/Examples/FLOW_Richards_1D_Celia1990.py | 2 +- SimPEG/Examples/Forward_BasicDirectCurrent.py | 7 +- SimPEG/Mesh/TreeMesh.py | 33 +++++++-- SimPEG/Mesh/View.py | 68 ++----------------- SimPEG/Tests.py | 2 +- SimPEG/Utils/__init__.py | 1 - SimPEG/Utils/ipythonutils.py | 28 -------- SimPEG/__init__.py | 2 +- docs/conf.py | 4 +- setup.py | 2 +- 13 files changed, 50 insertions(+), 107 deletions(-) delete mode 100644 SimPEG/Utils/ipythonutils.py diff --git a/.bumpversion.cfg b/.bumpversion.cfg index f5efbf0d..ea37cced 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 0.1.4 +current_version = 0.1.9 files = setup.py SimPEG/__init__.py docs/conf.py diff --git a/SimPEG/EM/Analytics/FDEM.py b/SimPEG/EM/Analytics/FDEM.py index ce7e623d..9e776fdf 100644 --- a/SimPEG/EM/Analytics/FDEM.py +++ b/SimPEG/EM/Analytics/FDEM.py @@ -2,7 +2,6 @@ from __future__ import division import numpy as np from scipy.constants import mu_0, pi from scipy.special import erf -import matplotlib.pyplot as plt from SimPEG import Utils diff --git a/SimPEG/Examples/EM_FDEM_1D_Inversion.py b/SimPEG/Examples/EM_FDEM_1D_Inversion.py index fdf2750e..aba70f4b 100644 --- a/SimPEG/Examples/EM_FDEM_1D_Inversion.py +++ b/SimPEG/Examples/EM_FDEM_1D_Inversion.py @@ -1,7 +1,7 @@ from SimPEG import * import SimPEG.EM as EM from scipy.constants import mu_0 -import matplotlib.pyplot as plt + def run(plotIt=True): """ @@ -31,6 +31,7 @@ def run(plotIt=True): if plotIt: + import matplotlib.pyplot as plt fig, ax = plt.subplots(1,1, figsize = (3, 6)) plt.semilogx(sigma[active], mesh.vectorCCz[active]) ax.set_ylim(-600, 0) @@ -60,6 +61,7 @@ def run(plotIt=True): survey.Wd = 1/(abs(survey.dobs)*std) if plotIt: + import matplotlib.pyplot as plt fig, ax = plt.subplots(1,1, figsize = (10, 6)) ax.loglog(rx.times, dtrue, 'b.-') ax.loglog(rx.times, survey.dobs, 'r.-') @@ -88,6 +90,7 @@ def run(plotIt=True): mopt = inv.run(m0) if plotIt: + import matplotlib.pyplot as plt fig, ax = plt.subplots(1,1, figsize = (3, 6)) plt.semilogx(sigma[active], mesh.vectorCCz[active]) plt.semilogx(np.exp(mopt), mesh.vectorCCz[active]) diff --git a/SimPEG/Examples/FLOW_Richards_1D_Celia1990.py b/SimPEG/Examples/FLOW_Richards_1D_Celia1990.py index 7c663e6b..4c90ea7b 100644 --- a/SimPEG/Examples/FLOW_Richards_1D_Celia1990.py +++ b/SimPEG/Examples/FLOW_Richards_1D_Celia1990.py @@ -1,6 +1,5 @@ from SimPEG import * from SimPEG.FLOW import Richards -import matplotlib.pyplot as plt def run(plotIt=True): """ @@ -61,6 +60,7 @@ def run(plotIt=True): Hs_H120= getFields(120.,'head') if not plotIt:return + import matplotlib.pyplot as plt plt.figure(figsize=(13,5)) plt.subplot(121) plt.plot(40-M.gridCC, Hs_M10[-1],'b-') diff --git a/SimPEG/Examples/Forward_BasicDirectCurrent.py b/SimPEG/Examples/Forward_BasicDirectCurrent.py index 06c9e79e..efbb287c 100644 --- a/SimPEG/Examples/Forward_BasicDirectCurrent.py +++ b/SimPEG/Examples/Forward_BasicDirectCurrent.py @@ -1,7 +1,4 @@ from SimPEG import Mesh, Utils, np, SolverLU -import matplotlib.pyplot as plt -import matplotlib -from matplotlib.mlab import griddata ## 2D DC forward modeling example with Tensor and Curvilinear Meshes @@ -39,6 +36,10 @@ def run(plotIt=True): if not plotIt: return + import matplotlib.pyplot as plt + import matplotlib + from matplotlib.mlab import griddata + #Step4: Making Figure fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2)) label = ["(a)", "(b)"] diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 997f7be9..1d5c8c8c 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -90,11 +90,6 @@ # from SimPEG import np, sp, Utils, Solver -import matplotlib.pyplot as plt -import matplotlib -from mpl_toolkits.mplot3d import Axes3D -import matplotlib.colors as colors -import matplotlib.cm as cmx try: import TreeUtils @@ -1973,6 +1968,13 @@ class TreeMesh(BaseTensorMesh, InnerProducts): facesX=False, facesY=False, facesZ=False, edgesX=False, edgesY=False, edgesZ=False): + + import matplotlib.pyplot as plt + import matplotlib + from mpl_toolkits.mplot3d import Axes3D + import matplotlib.colors as colors + import matplotlib.cm as cmx + # self.number() axOpts = {'projection':'3d'} if self.dim == 3 else {} @@ -2094,6 +2096,13 @@ class TreeMesh(BaseTensorMesh, InnerProducts): def plotImage(self, I, ax=None, showIt=False, grid=False, clim=None): if self.dim == 3: raise Exception('Use plot slice?') + + import matplotlib.pyplot as plt + import matplotlib + from mpl_toolkits.mplot3d import Axes3D + import matplotlib.colors as colors + import matplotlib.cm as cmx + if ax is None: ax = plt.subplot(111) jet = cm = plt.get_cmap('jet') cNorm = colors.Normalize( @@ -2123,6 +2132,13 @@ class TreeMesh(BaseTensorMesh, InnerProducts): assert vType in ['CC','F','E'] assert self.dim == 3 + + import matplotlib.pyplot as plt + import matplotlib + from mpl_toolkits.mplot3d import Axes3D + import matplotlib.colors as colors + import matplotlib.cm as cmx + szSliceDim = len(getattr(self, 'h'+normal.lower())) #: Size of the sliced dimension if ind is None: ind = int(szSliceDim/2) assert type(ind) in [int, long], 'ind must be an integer' @@ -2269,6 +2285,13 @@ class CellLookUpException(TreeException): if __name__ == '__main__': + + import matplotlib.pyplot as plt + import matplotlib + from mpl_toolkits.mplot3d import Axes3D + import matplotlib.colors as colors + import matplotlib.cm as cmx + def topo(x): return np.sin(x*(2.*np.pi))*0.3 + 0.5 diff --git a/SimPEG/Mesh/View.py b/SimPEG/Mesh/View.py index b078eb66..089d7d9a 100644 --- a/SimPEG/Mesh/View.py +++ b/SimPEG/Mesh/View.py @@ -1,8 +1,11 @@ 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 +try: + import matplotlib.pyplot as plt + import matplotlib + from mpl_toolkits.mplot3d import Axes3D +except ImportError, e: + print 'Trouble importing matplotlib.' class TensorView(object): @@ -479,63 +482,6 @@ class TensorView(object): ax.grid(True) if showIt: plt.show() - def slicer(mesh, var, imageType='CC', normal='z', index=0, ax=None, clim=None): - assert normal in 'xyz', 'normal must be x, y, or z' - if ax is None: ax = plt.subplot(111) - I = mesh.r(var,'CC','CC','M') - axes = [p for p in 'xyz' if p not in normal.lower()] - if normal is 'x': I = I[index,:,:] - if normal is 'y': I = I[:,index,:] - if normal is 'z': I = I[:,:,index] - if clim is None: clim = [I.min(),I.max()] - p = ax.pcolormesh(getattr(mesh,'vectorN'+axes[0]),getattr(mesh,'vectorN'+axes[1]),I.T,vmin=clim[0],vmax=clim[1]) - ax.axis('tight') - ax.set_xlabel(axes[0]) - ax.set_ylabel(axes[1]) - return p - - def videoSlicer(mesh,var,imageType='CC',normal='z',figsize=(10,8)): - assert mesh.dim > 2, 'This is for 3D meshes only.' - # First set up the figure, the axis, and the plot element we want to animate - fig = plt.figure(figsize=figsize) - ax = plt.axes() - clim = [var.min(),var.max()] - plt.colorbar(mesh.slicer(var, imageType=imageType, normal=normal, index=0, ax=ax, clim=clim)) - tlt = plt.title(normal) - - def animateFrame(i): - mesh.slicer(var, imageType=imageType, normal=normal, index=i, ax=ax, clim=clim) - tlt.set_text(normal.upper()+('-Slice: %d, %4.4f' % (i,getattr(mesh,'vectorCC'+normal)[i]))) - - return animate(fig, animateFrame, frames=mesh.vnC['xyz'.index(normal)]) - - def video(mesh, var, function, figsize=(10, 8), colorbar=True, skip=1): - """ - Call a function for a list of models to create a video. - - :: - - def function(var, ax, clim, tlt, i): - tlt.set_text('%d'%i) - return mesh.plotImage(var, imageType='CC', ax=ax, clim=clim) - - mesh.video([model1, model2, ..., modeln],function) - """ - # First set up the figure, the axis, and the plot element we want to animate - fig = plt.figure(figsize=figsize) - ax = plt.axes() - VAR = np.concatenate(var) - clim = [VAR.min(),VAR.max()] - tlt = plt.title('') - if colorbar: - plt.colorbar(function(var[0],ax,clim,tlt,0)) - - frames = np.arange(0,len(var),skip) - def animateFrame(j): - i = frames[j] - function(var[i],ax,clim,tlt,i) - - return animate(fig, animateFrame, frames=len(frames)) class CylView(object): diff --git a/SimPEG/Tests.py b/SimPEG/Tests.py index 6d414441..804ca6b8 100644 --- a/SimPEG/Tests.py +++ b/SimPEG/Tests.py @@ -1,5 +1,4 @@ import numpy as np -import matplotlib.pyplot as plt from numpy.linalg import norm from SimPEG.Utils import mkvc, sdiag, diagEst from SimPEG import Utils @@ -311,6 +310,7 @@ def checkDerivative(fctn, x0, num=7, plotIt=True, dx=None, expectedOrder=2, tole if plotIt: + import matplotlib.pyplot as plt ax = ax or plt.subplot(111) ax.loglog(h, E0, 'b') ax.loglog(h, E1, 'g--') diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index 5280ae79..250146c1 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -3,7 +3,6 @@ from codeutils import * from meshutils import exampleLrmGrid, meshTensor, closestPoints, readUBCTensorMesh, writeUBCTensorMesh, writeUBCTensorModel, readVTRFile, writeVTRFile from curvutils import volTetra, faceInfo, indexCube from interputils import interpmat -from ipythonutils import easyAnimate as animate from CounterUtils import * import ModelBuilder import SolverUtils diff --git a/SimPEG/Utils/ipythonutils.py b/SimPEG/Utils/ipythonutils.py deleted file mode 100644 index 7b66e131..00000000 --- a/SimPEG/Utils/ipythonutils.py +++ /dev/null @@ -1,28 +0,0 @@ -from tempfile import NamedTemporaryFile -import matplotlib.pyplot as plt -from matplotlib import animation - -# http://jakevdp.github.io/blog/2013/05/12/embedding-matplotlib-animations/ -# http://www.renevolution.com/how-to-install-ffmpeg-on-mac-os-x/ - -VIDEO_TAG = """""" - -def anim_to_html(anim): - if not hasattr(anim, '_encoded_video'): - with NamedTemporaryFile(suffix='.mp4') as f: - anim.save(f.name, fps=20, extra_args=['-vcodec', 'libx264', '-pix_fmt', 'yuv420p']) - video = open(f.name, "rb").read() - anim._encoded_video = video.encode("base64") - - return VIDEO_TAG.format(anim._encoded_video) - -def display_animation(anim): - plt.close(anim._fig) - return anim_to_html(anim) - -animation.Animation._repr_html_ = display_animation - -easyAnimate = animation.FuncAnimation diff --git a/SimPEG/__init__.py b/SimPEG/__init__.py index 94bf255f..cc51fd1f 100644 --- a/SimPEG/__init__.py +++ b/SimPEG/__init__.py @@ -15,7 +15,7 @@ import Directives import Inversion import Tests -__version__ = '0.1.4' +__version__ = '0.1.9' __author__ = 'Rowan Cockett' __license__ = 'MIT' __copyright__ = 'Copyright 2014 Rowan Cockett' diff --git a/docs/conf.py b/docs/conf.py index 4f3f4462..fee262de 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -51,9 +51,9 @@ copyright = u'2013, SimPEG Developers' # built documents. # # The short X.Y version. -version = '0.1.4' +version = '0.1.9' # The full version, including alpha/beta/rc tags. -release = '0.1.4' +release = '0.1.9' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 34c29703..bcb5b8e3 100644 --- a/setup.py +++ b/setup.py @@ -77,7 +77,7 @@ with open("README.rst") as f: setup( name = "SimPEG", - version = "0.1.4", + version = "0.1.9", packages = find_packages(), install_requires = ['numpy>=1.7', 'scipy>=0.13', From f482f9d87715c1d02e09ebf2ea3aba8b6ce281a9 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Sun, 10 Jan 2016 15:16:46 -0800 Subject: [PATCH 16/19] Rearrange tests in order of speed for travis. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index db79b031..258c4b7b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,12 +16,12 @@ addons: env: - TEST_DIR="tests/mesh tests/base tests/utils" - - TEST_DIR=tests/examples - - TEST_DIR=tests/em/fdem/forward - TEST_DIR=tests/em/fdem/inverse/derivs - - TEST_DIR=tests/em/fdem/inverse/adjoint - TEST_DIR=tests/em/tdem - TEST_DIR=tests/flow + - TEST_DIR=tests/examples + - TEST_DIR=tests/em/fdem/inverse/adjoint + - TEST_DIR=tests/em/fdem/forward # Setup anaconda before_install: From 8a61259cab83ab66753a70a665e499afb67e2c1f Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Sun, 10 Jan 2016 15:17:13 -0800 Subject: [PATCH 17/19] Remove out of date GCE folder. --- GCEtools/PETScIO.py | 470 ------------------------------------ GCEtools/PetscExample.ipynb | 198 --------------- GCEtools/gceStartup.txt | 11 - GCEtools/petscStartup.sh | 145 ----------- GCEtools/startup.sh | 22 -- 5 files changed, 846 deletions(-) delete mode 100644 GCEtools/PETScIO.py delete mode 100644 GCEtools/PetscExample.ipynb delete mode 100644 GCEtools/gceStartup.txt delete mode 100755 GCEtools/petscStartup.sh delete mode 100644 GCEtools/startup.sh diff --git a/GCEtools/PETScIO.py b/GCEtools/PETScIO.py deleted file mode 100644 index 0977d59a..00000000 --- a/GCEtools/PETScIO.py +++ /dev/null @@ -1,470 +0,0 @@ -#!/usr/bin/python -""" -Input and output functions. -""" - - -import os as _os -import errno as _errno -import sys as _sys -import numpy as _np - -from petsc4py import PETSc as _PETSc -import fileinput as _fl - -def vecToArray(obj): - """ Converts a PETSc vector to a numpy array, available on *all* MPI nodes. - - Args: - obj (petsc4py.PETSc.Vec): input vector. - - Returns: - numpy.array : - """ - # scatter vector 'obj' to all processes - comm = obj.getComm() - scatter, obj0 = _PETSc.Scatter.toAll(obj) - scatter.scatter(obj, obj0, False, _PETSc.Scatter.Mode.FORWARD) - - return _np.asarray(obj0) - - # deallocate - comm.barrier() - scatter.destroy() - obj0.destroy() - - -def vecToArray0(obj): - """ Converts a PETSc vector to a numpy array available on MPI node 0. - - Args: - obj (petsc4py.PETSc.Vec): input vector. - - Returns: - numpy.array : - """ - # scatter vector 'obj' to process 0 - comm = obj.getComm() - rank = comm.getRank() - scatter, obj0 = _PETSc.Scatter.toZero(obj) - scatter.scatter(obj, obj0, False, _PETSc.Scatter.Mode.FORWARD) - - if rank == 0: return _np.asarray(obj0) - - # deallocate - comm.barrier() - scatter.destroy() - obj0.destroy() - - -def arrayToVec(vecArray): - """ Converts a (global) array to a PETSc vector over :attr:`petsc4py.PETSc.COMM_WORLD`. - - Args: - vecArray (array or numpy.array): input vector. - - Returns: - petsc4py.PETSc.Vec() : - """ - vec = _PETSc.Vec().create(comm=_PETSc.COMM_WORLD) - vec.setSizes(len(vecArray)) - vec.setUp() - (Istart,Iend) = vec.getOwnershipRange() - return vec.createWithArray(vecArray[Istart:Iend], - comm=_PETSc.COMM_WORLD) - vec.destroy() - - -def arrayToMat(matArray): - """ Converts a (global) 2D array to a PETSc matrix over :attr:`petsc4py.PETSc.COMM_WORLD`. - - Args: - matArray (array or numpy.array): input square array. - - :rtype: petsc4py.PETSc.Mat() - - .. important:: - Requires `SciPy `_. - - """ - try: - import scipy.sparse as sparse - except: - print '\nERROR: loading matrices from txt files requires Scipy!' - return - - matSparse =matArray - - mat = _PETSc.Mat().createAIJ(size=matSparse.shape,comm=_PETSc.COMM_WORLD) - (Istart,Iend) = mat.getOwnershipRange() - - ai = matSparse.indptr[Istart:Iend+1] - matSparse.indptr[Istart] - aj = matSparse.indices[matSparse.indptr[Istart]:matSparse.indptr[Iend]] - av = matSparse.data[matSparse.indptr[Istart]:matSparse.indptr[Iend]] - - mat.setValuesCSR(ai,aj,av) - mat.assemble() - - return mat - mat.destroy() - -def matToSparse(mat): - """ Converts a PETSc matrix to a (global) sparse matrix. - - Args: - mat (petsc4py.PETSc.Mat): input PETSc matrix. - - :rtype: scipy.sparse.csr_matrix - - .. important:: - Requires `SciPy `_. - - """ - import scipy.sparse as sparse - - data = mat.getValuesCSR() - - (Istart,Iend) = mat.getOwnershipRange() - columns = mat.getSize()[0] - sparseSubMat = sparse.csr_matrix(data[::-1],shape=(Iend-Istart,columns)) - - comm = _PETSc.COMM_WORLD - - sparseSubMat = comm.tompi4py().allgather(sparseSubMat) - - return sparse.vstack(sparseSubMat) - -def adjToH(adj,d=[0],amp=[0.]): - """ Creates a 1 particle PETSc-type Hamiltonian matrix from a PETSc adjacency matrix. - - Args: - adj (petsc4py.PETSc.Mat): input PETSc-type adjacency matrix. - - d (array of ints): an array containing *integers* indicating the nodes - where diagonal defects are to be placed (e.g. ``d=[0,1,4]``). - - amp (array of floats): an array containing *floats* indicating the diagonal defect - amplitudes corresponding to each element in ``d`` (e.g. ``amp=[0.5,-1,4.2]``). - - Returns: - : 1 particle Hamiltonian matrix - :rtype: petsc4py.PETSc.Mat() - - Warning: - * The size of ``a`` and ``d`` must be identical - - >>> amp = [0.5,-1.,4.2] - >>> len(d) == len(amp) - True - - * Elements of ``d`` can range from :math:`[0,N-1]` where the adjacency matrix is :math:`N\\times N`. - - """ - (Istart,Iend) = adj.getOwnershipRange() - diagSum = [] - for i in range(Istart,Iend): - diagSum.append(_np.sum(adj.getRow(i)[-1])) - for j,val in enumerate(d): - if i==val: diagSum[i-Istart] += amp[j] - - mat = _PETSc.Mat().create(comm=_PETSc.COMM_WORLD) - mat.setSizes(adj.getSize()) - mat.setUp() - - for i in range(Istart,Iend): - mat.setValue(i,i,diagSum[i-Istart]) - - mat.assemble() - mat.axpy(-1,adj) - - return mat - mat.destroy() - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#---------------------- Vec I/O functions --------------------------- -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -def exportVec(vec,filename,filetype): - """ Export a PETSc vector to a file. - - Args: - vec (petsc4py.PETSc.Vec): input vector. - filename (str): path to desired output file. - filetype (str): the filetype of the exported vector. - - * ``'txt'`` - a column vector in text format. - * ``'bin'`` - a PETSc binary vector. - """ - if _os.path.isabs(filename): - outDir = _os.path.dirname(filename) - else: - outDir = './'+_os.path.dirname(filename) - - # create output directory if it doesn't exist - try: - _os.mkdir(outDir) - except OSError as exception: - if exception.errno != _errno.EEXIST: - raise - - if filetype == 'txt': - # scatter prob to process 0 - comm = vec.getComm() - rank = comm.getRank() - scatter, vec0 = _PETSc.Scatter.toZero(vec) - scatter.scatter(vec, vec0, False, _PETSc.Scatter.Mode.FORWARD) - - # use process 0 to write to text file - if rank == 0: - array0 = _np.asarray(vec0) - with open(filename,'w') as f: - for i in range(len(array0)): - f.write('{0: .12e}\n'.format(array0[i])) - - # deallocate - comm.barrier() - scatter.destroy() - vec0.destroy() - - elif filetype == 'bin': - binSave = _PETSc.Viewer().createBinary(filename, 'w') - binSave(vec) - binSave.destroy() - - vec.comm.barrier() - -def loadVec(filename,filetype): - """ Import a PETSc vector from a file. - - Args: - filename (str): path to input file. - filetype (str): the filetype. - - * ``'txt'`` - a column vector in text format. - * ``'bin'`` - a PETSc binary vector. - """ - if filetype == 'txt': - try: - vecArray = _np.loadtxt(filename,dtype=_PETSc.ScalarType) - return arrayToVec(vecArray) - except: - print "\nERROR: input state space file " + filename\ - + " does not exist or is in an incorrect format" - _sys.exit() - - elif filetype == 'bin': - binLoad = _PETSc.Viewer().createBinary(filename, 'r') - try: - return _PETSc.Vec().load(binLoad) - except: - print "\nERROR: input state space file " + filename\ - + " does not exist or is in an incorrect format" - _sys.exit() - binLoad.destroy() - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#---------------------- Mat I/O functions --------------------------- -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -def exportMat(mat,filename,filetype,mattype=None): - """ Export a PETSc matrix to a file. - - Args: - mat (petsc4py.PETSc.Mat): input matrix. - filename (str): path to desired output file. - filetype (str): the filetype of the exported vector. - - * ``'txt'`` - a 2D matrix array in text format. - * ``'bin'`` - a PETSc binary matrix. - mattype (str): (``None``,``'adj'``) - if set to ``adj``, only - integers ``0`` and ``1`` are written. Note - that this only applied in ``txt`` mode. - """ - rank = _PETSc.Comm.Get_rank(_PETSc.COMM_WORLD) - - if _os.path.isabs(filename): - outDir = _os.path.dirname(filename) - else: - outDir = './'+_os.path.dirname(filename) - - # create output directory if it doesn't exist - try: - _os.mkdir(outDir) - except OSError as exception: - if exception.errno != _errno.EEXIST: - raise - - if filetype == 'txt': - txtSave = _PETSc.Viewer().createASCII(filename, 'w', - format=_PETSc.Viewer.Format.ASCII_DENSE, comm=_PETSc.COMM_WORLD) - txtSave(mat) - txtSave.destroy() - - if rank == 0: - for line in _fl.FileInput(filename,inplace=1): - if line[2] != 't': - if mattype == 'adj': - line = line.replace(" i","j") - line = line.replace(" -","-") - line = line.replace("+-","-") - line = line.replace("0000e+01+0.00000e+00j","") - line = line.replace(".00000e+00+0.00000e+00j","") - line = line.replace(".","") - line = line.replace(" -","\t-") - line = line.replace(" ","\t") - line = line.replace(" ","") - line = line.replace("\t"," ") - print line, - else: - line = line.replace(" i","j") - line = line.replace(" -","-") - line = line.replace("+-","-") - print line, - - elif filetype == 'bin': - binSave = _PETSc.Viewer().createBinary(filename, 'w', comm=_PETSc.COMM_WORLD) - binSave(mat) - binSave.destroy() - - mat.comm.barrier() - -def loadMat(filename,filetype,delimiter=None): - """ Import a PETSc matrix from a file. - - Args: - filename (str): path to input file. - filetype (str): the filetype. - - * ``'txt'`` - a 2D matrix array in text format. - * ``'bin'`` - a PETSc matrix vector. - - delimiter (str): this is passed to `numpy.genfromtxt\ - `_ - in the case of strange delimiters in an imported ``txt`` file. - """ - if filetype == 'txt': - try: - try: - if delimiter is None: - matArray = _np.genfromtxt(filename,dtype=_PETSc.ScalarType) - else: - matArray = _np.genfromtxt(filename,dtype=_PETSc.ScalarType,delimiter=delimiter) - except: - filefix = [] - for line in _fl.FileInput(filename,inplace=0): - if line[2] != 't': - line = line.replace(" i","j") - line = line.replace(" -","-") - line = line.replace("+-","-") - filefix.append(line) - - matArray = _np.genfromtxt(filefix,dtype=_PETSc.ScalarType) - - return arrayToMat(matArray) - except: - print "\nERROR: input state space file " + filename\ - + " does not exist or is in an incorrect format" - _sys.exit() - - elif filetype == 'bin': - binLoad = _PETSc.Viewer().createBinary(filename, 'r') - try: - return _PETSc.Mat().load(binLoad) - except: - print "\nERROR: input state space file " + filename\ - + " does not exist or is in an incorrect format" - _sys.exit() - binLoad.destroy() - -def exportVecToMat(vec,filename,filetype): - """ Export a :math:`N^2` element PETSc vector as a :math:`N\\times N` matrix. - - This is useful when wanting to view the full statespace of a 2 particle - quantum walk. - - Args: - vec (petsc4py.PETSc.Vec): input :math:`N^2` element vector. - filename (str): path to desired output file. - filetype (str): the filetype of the exported vector. - - * ``'txt'`` - an :math:`N\\times N` 2D matrix array in text format. - * ``'bin'`` - an :math:`N\\times N` PETSc binary matrix. - """ - rank = _PETSc.Comm.Get_rank(_PETSc.COMM_WORLD) - - if _os.path.isabs(filename): - outDir = _os.path.dirname(filename) - else: - outDir = './'+_os.path.dirname(filename) - - # create output directory if it doesn't exist - try: - _os.mkdir(outDir) - except OSError as exception: - if exception.errno != _errno.EEXIST: - raise - - vecArray = vecToArray(vec) - matArray = vecArray.reshape([_np.sqrt(vecArray.size),_np.sqrt(vecArray.size)]) - - if filetype == 'txt': - #if rank == 0: _np.savetxt(filename,matArray) - txtSave = _PETSc.Viewer().createASCII(filename, 'w', - format=_PETSc.Viewer.Format.ASCII_DENSE, comm=_PETSc.COMM_WORLD) - txtSave(arrayToMat(matArray)) - txtSave.destroy() - - if rank == 0: - for line in _fl.FileInput(filename,inplace=1): - if line[2] != 't': - line = line.replace(" i","j") - line = line.replace(" -","-") - line = line.replace("+-","-") - print line, - - elif filetype == 'bin': - binSave = _PETSc.Viewer().createBinary(filename, 'w', comm=_PETSc.COMM_WORLD) - binSave(arrayToMat(matArray)) - binSave.destroy() - vec.comm.barrier() - - -def loadMatToVec(filename,filetype): - """ Load a :math:`N\\times N` matrix as a :math:`N^2` element PETSc vector. - - This is useful when wanting to import the full statespace of a 2 particle - quantum walk to use for propagation. - - Args: - filename (str): path to the input file. - filetype (str): the filetype - - * ``'txt'`` - an :math:`N\\times N` 2D matrix array in text format. - * ``'bin'`` - **Not yet implemented! Please use a txt \ - format for this type of import**. - """ - if filetype == 'txt': - try: - try: - matArray = _np.loadtxt(filename,dtype=_PETSc.ScalarType) - except: - filefix = [] - for line in _fl.FileInput(filename,inplace=0): - if line[2] != 't': - line = line.replace(" i","j") - line = line.replace(" -","-") - line = line.replace("+-","-") - filefix.append(line) - - matArray = _np.loadtxt(filefix,dtype=_PETSc.ScalarType) - - vecArray = matArray.reshape(matArray.shape[0]**2) - return arrayToVec(vecArray) - except: - print "\nERROR: input state space file " + filename\ - + " does not exist or is in an incorrect format" - _sys.exit() - - elif filetype == 'bin': - print '\nERROR: only works for txt storage!' - _sys.exit() diff --git a/GCEtools/PetscExample.ipynb b/GCEtools/PetscExample.ipynb deleted file mode 100644 index 40e960ea..00000000 --- a/GCEtools/PetscExample.ipynb +++ /dev/null @@ -1,198 +0,0 @@ -{ - "metadata": { - "name": "" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from SimPEG import *\n", - "%pylab inline" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Populating the interactive namespace from numpy and matplotlib\n" - ] - } - ], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "M = mesh.TensorMesh([20,30]) \n", - "A = M.faceDiv*M.faceDiv.T + sp.identity(M.nC)\n", - "b = np.random.rand(M.nC)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 35 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "phi = Solver(A).solve(b)\n", - "colorbar(M.plotImage(phi))" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 37, - "text": [ - "" - ] - }, - { - "metadata": {}, - "output_type": "display_data", - "png": "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\n", - "text": [ - "" - ] - } - ], - "prompt_number": 37 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "print np.linalg.norm(A*phi-b)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "1.5220841846e-13\n" - ] - } - ], - "prompt_number": 38 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import petsc4py\n", - "import sys\n", - "petsc4py.init(sys.argv)\n", - "from petsc4py import PETSc" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 39 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import PETScIO as IO\n", - "Apetsc = PETSc.Mat().createAIJ(size=A.shape,csr=(A.indptr, A.indices, A.data))\n", - "bpetsc = IO.arrayToVec(b)\n", - "xpetsc = IO.arrayToVec(0*b)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 40 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "ksp = PETSc.KSP().create()\n", - "pc = PETSc.PC().create()\n", - "\n", - "ksp.setOperators(Apetsc)\n", - "\n", - "ksp.setType(ksp.Type.CG)\n", - "pc = ksp.getPC()\n", - "pc.setType(pc.Type.HYPRE)\n", - "ksp.view()\n", - "\n", - "ksp.solve(bpetsc, xpetsc)\n", - "print ksp.its" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "3\n" - ] - } - ], - "prompt_number": 76 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "X = IO.vecToArray(xpetsc)\n", - "print np.linalg.norm(A*X-b)\n", - "M.plotImage(X)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "0.000199616893249\n" - ] - }, - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 77, - "text": [ - "" - ] - }, - { - "metadata": {}, - "output_type": "display_data", - "png": "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\nrkJggg==\n", - "text": [ - "" - ] - } - ], - "prompt_number": 77 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [] - } - ], - "metadata": {} - } - ] -} \ No newline at end of file diff --git a/GCEtools/gceStartup.txt b/GCEtools/gceStartup.txt deleted file mode 100644 index 76bbcb39..00000000 --- a/GCEtools/gceStartup.txt +++ /dev/null @@ -1,11 +0,0 @@ -# Check project status -gcutil getproject --project= --cache_flag_values - -# Start an instance -gcutil addinstance - -# Log in -gcutil ssh - -# Shut down -gcutil deleteinstance \ No newline at end of file diff --git a/GCEtools/petscStartup.sh b/GCEtools/petscStartup.sh deleted file mode 100755 index 147ae6ea..00000000 --- a/GCEtools/petscStartup.sh +++ /dev/null @@ -1,145 +0,0 @@ -#! /bin/bash - -locale-gen en_US en_US.UTF-8 hu_HU hu_HU.UTF-8 > output.t -dpkg-reconfigure locales >> output.t - -sudo apt-get update >> output.t -echo " " -echo " " -echo " ============================================" -echo " | Installing packages form package manager |" -echo " ============================================" -echo " " -echo " " - -sudo apt-get -y install aptitude >> output.t - -packages=(gcc gfortran git libopenmpi-dev python-pip python-dev git flex bison cmake vim cython ipython python-scipy python-numpy python-nose python-pip python-matplotlib python-vtk python-h5py libmumps-ptscotch-4.10.0 libmumps-ptscotch-dev libblas-dev liblapack-dev ) - - -for item in ${packages[*]} -do - printf " %-30s\n" $item - -done - -for item in ${packages[*]} -do - tput cuu1 -done - -for item in ${packages[*]} -do - sudo aptitude -y install $item >> output.t - printf " %-30s %-4s\n" $item done -done - - -echo " " -echo " " -echo " =====================================" -echo " | Installing extra Python libraries |" -echo " =====================================" -echo " " -echo " " - - -pipPackages=(mpi4py pymumps) - -for item in ${pipPackages[*]} -do - printf " %-30s\n" $item -done - -for item in ${pipPackages[*]} -do - tput cuu1 -done - -for item in ${pipPackages[*]} -do - sudo pip install $item >> output.t - printf " %-30s %-4s\n" $item done -done - -Upgrade=(scipy numpy ipython) - -for item in ${Upgrade[*]} -do - printf " %-8s%-7s\n" $item upgrade - -done - -for item in ${Upgrade[*]} -do - tput cuu1 -done - -for item in ${Upgrade[*]} -do - sudo pip install $item --upgrade >> output.t - printf " %-8s%-7s %-4s\n" $item upgrade done -done - - - -echo " " -echo " " -echo " =====================" -echo " | Installing SimPEG |" -echo " =====================" -echo " " -echo " " -cd ~ - - -git clone https://github.com/simpeg/simpeg.git >> output.t -cd simpeg/SimPEG/ -python setup.py >> output.t -cd ~ - -mkdir petsc -cd petsc - -echo " " -echo " " -echo " ====================" -echo " | Installing PETSc |" -echo " ====================" -echo " " -echo " " -wget http://ftp.mcs.anl.gov/pub/petsc/release-snapshots/petsc-3.4.3.tar.gz - -tar -zxf petsc-3.4.3.tar.gz - -cd petsc-3.4.3 - -./configure --with-debugging=no --dowload-mpich=yes --download-blacs=yes --download-f-blas-lapack=yes --download-scalapack=yes --download-mumps=yes --download-ml=yes --download-spooles=yes --download-hypre=yes --dowload-trilinos=yes --download-metis=yes --download-parmetis=yes --download-umfpack=yes --download-ptscotch=yes --download-superlu=yes --download-superlu_dist=yes --download-essl=yes --download-eucild=yes --download-spai=yes --download-mpi4py=yes --download-petsc4py=yes --download-scientificpython=yes - - -echo "export PETSC_DIR=/home/${USER}/petsc/petsc-3.4.3" >> ~/.bashrc -echo "export PETSC_ARCH=arch-linux2-c-opt" >> ~/.bashrc -export PETSC_DIR=/home/${USER}/petsc/petsc-3.4.3 -export PETSC_ARCH=arch-linux2-c-opt -. ~/.bashrc - -make PETSC_DIR=/home/${USER}/petsc/petsc-3.4.3 PETSC_ARCH=arch-linux2-c-opt all -make PETSC_DIR=/home/${USER}/petsc/petsc-3.4.3 PETSC_ARCH=arch-linux2-c-opt test - -cd ~/petsc -echo " " -echo " " -echo " =======================" -echo " | Installing PETSc4PY |" -echo " =======================" -echo " " -echo " " -git clone https://bitbucket.org/petsc/petsc4py.git -cd petsc4py/ -python setup.py build >> output.t -python setup.py install --prefix=~/petsc >> output.t - -echo "export PYTHONPATH=~/petsc/lib/python2.7/site-packages:/home/$USER/simpeg:${PYTHONPATH}" >> ~/.bashrc - -cd ~ -source ~/.bashrc diff --git a/GCEtools/startup.sh b/GCEtools/startup.sh deleted file mode 100644 index 91797960..00000000 --- a/GCEtools/startup.sh +++ /dev/null @@ -1,22 +0,0 @@ -#! /bin/bash -sudo aptitude -y update -sudo aptitude -y upgrade -sudo aptitude -y install gcc gfortran git libopenmpi-dev python-pip python-dev -sudo aptitude -y install ipython python-scipy python-numpy python-nose python-pip python-matplotlib -sudo aptitude -y install libmumps-ptscotch-4.10.0 libmumps-ptscotch-dev -sudo aptitude -y install libblas-dev liblapack-dev - -sudo pip install mpi4py -sudo pip install pymumps - -sudo pip install scipy --upgrade -sudo pip install numpy --upgrade -sudo pip install ipython --upgrade - -git clone https://github.com/simpeg/simpeg.git -cd simpeg/SimPEG/ -python setup.py -cd ~ - -echo export PYTHONPATH=/home/$USER/simpeg/ >> .bashrc -source .bashrc From 2c5b19b7a09210483c8706e79f2d6cd7780d7124 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Sun, 10 Jan 2016 17:21:01 -0800 Subject: [PATCH 18/19] Updates to the documentation. --- AUTHORS.rst | 10 +- CITATION.rst | 5 +- LICENSE | 2 +- PROJECTS.rst | 36 ----- SimPEG/EM/Analytics/FDEM.py | 3 +- SimPEG/Regularization.py | 83 +---------- docs/InversionWorkflow-PreSimPEG.png | Bin 0 -> 50417 bytes docs/api_FiniteVolume.rst | 19 +++ docs/api_ForwardProblem.rst | 7 +- docs/{api_Inverse.rst => api_Inversion.rst} | 23 +-- docs/api_InversionComponents.rst | 11 ++ docs/api_Mesh.rst | 3 +- docs/api_MeshCode.rst | 20 +-- docs/api_Optimization.rst | 9 ++ docs/api_Regularization.rst | 100 +++++++++++++ docs/api_Utilities.rst | 10 ++ docs/api_Utils.rst | 9 +- docs/api_bigPicture.rst | 64 ++++++++- docs/api_installing.rst | 4 +- docs/api_license.rst | 17 --- docs/em/api_Utils.rst | 7 +- docs/em/index.rst | 5 +- docs/index.rst | 151 +++++++++----------- 23 files changed, 316 insertions(+), 282 deletions(-) delete mode 100644 PROJECTS.rst create mode 100644 docs/InversionWorkflow-PreSimPEG.png create mode 100644 docs/api_FiniteVolume.rst rename docs/{api_Inverse.rst => api_Inversion.rst} (56%) create mode 100644 docs/api_InversionComponents.rst create mode 100644 docs/api_Optimization.rst create mode 100644 docs/api_Regularization.rst create mode 100644 docs/api_Utilities.rst delete mode 100644 docs/api_license.rst diff --git a/AUTHORS.rst b/AUTHORS.rst index 2a7d1903..f5e5ff7b 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -1,9 +1,13 @@ -- Luz Angelica Caudillo-Mata, (`@lacmajedrez `_) - Rowan Cockett, (`@rowanc1 `_) -- Eldad Haber, (`@ehaber99 `_) - Lindsey Heagy, (`@lheagy `_) - Seogi Kang, (`@sgkang `_) -- Dave Marchant, (`@dwfmarchant `_) +- Brendan Smithyman, (`@bsmithyman `_) - Gudni Rosenkjaer, (`@grosenkj `_) +- Dom Fournier, (`@fourndo `_) +- Dave Marchant, (`@dwfmarchant `_) - Lars Ruthotto, (`@lruthotto `_) - Mike Wathen, (`@mrwathen `_) +- Luz Angelica Caudillo-Mata, (`@lacmajedrez `_) +- Eldad Haber, (`@ehaber99 `_) +- Doug Oldenburg, (`@dougoldenburg `_) +- Adam Pidlisecky, (`@aPid1 `_) diff --git a/CITATION.rst b/CITATION.rst index a3a13d7e..b0b2a76f 100644 --- a/CITATION.rst +++ b/CITATION.rst @@ -1,14 +1,13 @@ Citing SimPEG -============= +------------- -There is a paper about SimPEG! +There is a `paper about SimPEG `_, if you use this code, please help our scientific visibility by citing our work! Cockett, R., Kang, S., Heagy, L. J., Pidlisecky, A., & Oldenburg, D. W. (2015). SimPEG: An open source framework for simulation and gradient based parameter estimation in geophysical applications. Computers & Geosciences. BibTex: -------- .. code:: diff --git a/LICENSE b/LICENSE index 43ee31ab..c046b35d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2015 SimPEG Developers +Copyright (c) 2013-2016 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 diff --git a/PROJECTS.rst b/PROJECTS.rst deleted file mode 100644 index ce411d9d..00000000 --- a/PROJECTS.rst +++ /dev/null @@ -1,36 +0,0 @@ -- Electromagnetics (`simpegEM `_) - .. image:: https://travis-ci.org/simpeg/simpegem.svg?branch=master - :target: https://travis-ci.org/simpeg/simpegem - :alt: Master Branch - .. image:: https://coveralls.io/repos/simpeg/simpegem/badge.png?branch=master - :target: https://coveralls.io/r/simpeg/simpegem?branch=master -- Potential Fields (`simpegPF `_) - .. image:: https://travis-ci.org/simpeg/simpegpf.svg?branch=master - :target: https://travis-ci.org/simpeg/simpegpf - :alt: Master Branch - .. image:: https://coveralls.io/repos/simpeg/simpegpf/badge.png?branch=master - :target: https://coveralls.io/r/simpeg/simpegpf?branch=master -- Ground Water Flow (`simpegFLOW `_) - .. image:: https://travis-ci.org/simpeg/simpegflow.svg?branch=master - :target: https://travis-ci.org/simpeg/simpegflow - :alt: Master Branch - .. image:: https://coveralls.io/repos/simpeg/simpegflow/badge.png?branch=master - :target: https://coveralls.io/r/simpeg/simpegflow?branch=master -- Direct Current Resistivity (`simpegDC `_) - .. image:: https://travis-ci.org/simpeg/simpegdc.svg?branch=master - :target: https://travis-ci.org/simpeg/simpegdc - :alt: Master Branch - .. image:: https://coveralls.io/repos/simpeg/simpegdc/badge.png?branch=master - :target: https://coveralls.io/r/simpeg/simpegdc?branch=master -- Electromagnetics 1D (`simpegEM1D `_) - .. image:: https://travis-ci.org/simpeg/simpegEM1D.svg?branch=master - :target: https://travis-ci.org/simpeg/simpegEM1D - :alt: Master Branch - .. image:: https://coveralls.io/repos/simpeg/simpegEM1D/badge.png?branch=master - :target: https://coveralls.io/r/simpeg/simpegEM1D?branch=master -- Magnetotellurics (`simpegMT `_) - .. image:: https://travis-ci.org/simpeg/simpegmt.svg?branch=master - :target: https://travis-ci.org/simpeg/simpegmt - :alt: Master Branch - .. image:: https://coveralls.io/repos/simpeg/simpegmt/badge.png?branch=master - :target: https://coveralls.io/r/simpeg/simpegmt?branch=master diff --git a/SimPEG/EM/Analytics/FDEM.py b/SimPEG/EM/Analytics/FDEM.py index 9e776fdf..1f52459c 100644 --- a/SimPEG/EM/Analytics/FDEM.py +++ b/SimPEG/EM/Analytics/FDEM.py @@ -58,8 +58,9 @@ def MagneticDipoleWholeSpace(XYZ, srcLoc, sig, f, moment=1., orientation='X', mu from SimPEG import EM import matplotlib.pyplot as plt + from scipy.constants import mu_0 freqs = np.logspace(-2,5,100) - Bx, By, Bz = EM.Analytics.FDEM.AnalyticMagDipoleWholeSpace([0,100,0], [0,0,0], 1e-2, freqs, m=1, orientation='Z') + Bx, By, Bz = EM.Analytics.FDEM.MagneticDipoleWholeSpace([0,100,0], [0,0,0], 1e-2, freqs, moment=1, orientation='Z') plt.loglog(freqs, np.abs(Bz.real)/mu_0, 'b') plt.loglog(freqs, np.abs(Bz.imag)/mu_0, 'r') plt.legend(('real','imag')) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index e3506290..97b5e7a2 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -115,86 +115,7 @@ class BaseRegularization(object): 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: - - .. math:: - - R(m) = \int_\Omega \\frac{\\alpha_x}{2}\left(\\frac{\partial m}{\partial x}\\right)^2 + \\frac{\\alpha_y}{2}\left(\\frac{\partial m}{\partial y}\\right)^2 \partial v - - Our discrete gradient operator works on cell centers and gives the derivative on the cell faces, which is not where we want to be evaluating this integral. We need to average the values back to the cell-centers before we integrate. To avoid null spaces, we square first and then average. In 2D with ij notation it looks like this: - - .. math:: - - R(m) \\approx \sum_{ij} \left[\\frac{\\alpha_x}{2}\left[\left(\\frac{m_{i+1,j} - m_{i,j}}{h}\\right)^2 + \left(\\frac{m_{i,j} - m_{i-1,j}}{h}\\right)^2\\right] - + \\frac{\\alpha_y}{2}\left[\left(\\frac{m_{i,j+1} - m_{i,j}}{h}\\right)^2 + \left(\\frac{m_{i,j} - m_{i,j-1}}{h}\\right)^2\\right] - \\right]h^2 - - If we let D_1 be the derivative matrix in the x direction - - .. math:: - - \mathbf{D}_1 = \mathbf{I}_2\otimes\mathbf{d}_1 - - .. math:: - - \mathbf{D}_2 = \mathbf{d}_2\otimes\mathbf{I}_1 - - Where d_1 is the one dimensional derivative: - - .. math:: - - \mathbf{d}_1 = \\frac{1}{h} \left[ \\begin{array}{cccc} - -1 & 1 & & \\\\ - & \ddots & \ddots&\\\\ - & & -1 & 1\end{array} \\right] - - .. math:: - - R(m) \\approx \mathbf{v}^\\top \left[\\frac{\\alpha_x}{2}\mathbf{A}_1 (\mathbf{D}_1 m) \odot (\mathbf{D}_1 m) + \\frac{\\alpha_y}{2}\mathbf{A}_2 (\mathbf{D}_2 m) \odot (\mathbf{D}_2 m) \\right] - - Recall that this is really a just point wise multiplication, or a diagonal matrix times a vector. When we multiply by something in a diagonal we can interchange and it gives the same results (i.e. it is point wise) - - .. math:: - - \mathbf{a\odot b} = \\text{diag}(\mathbf{a})\mathbf{b} = \\text{diag}(\mathbf{b})\mathbf{a} = \mathbf{b\odot a} - - and the transpose also is true (but the sizes have to make sense...): - - .. math:: - - \mathbf{a}^\\top\\text{diag}(\mathbf{b}) = \mathbf{b}^\\top\\text{diag}(\mathbf{a}) - - So R(m) can simplify to: - - .. math:: - - R(m) \\approx \mathbf{m}^\\top \left[\\frac{\\alpha_x}{2}\mathbf{D}_1^\\top \\text{diag}(\mathbf{A}_1^\\top\mathbf{v}) \mathbf{D}_1 + \\frac{\\alpha_y}{2}\mathbf{D}_2^\\top \\text{diag}(\mathbf{A}_2^\\top \mathbf{v}) \mathbf{D}_2 \\right] \mathbf{m} - - We will define W_x as: - - .. math:: - - \mathbf{W}_x = \sqrt{\\alpha_x}\\text{diag}\left(\sqrt{\mathbf{A}_1^\\top\mathbf{v}}\\right) \mathbf{D}_1 - - - And then W as a tall matrix of all of the different regularization terms: - - .. math:: - - \mathbf{W} = \left[ \\begin{array}{c} - \mathbf{W}_s\\\\ - \mathbf{W}_x\\\\ - \mathbf{W}_y\end{array} \\right] - - Then we can write - - .. math:: - - R(m) \\approx \\frac{1}{2}\mathbf{m^\\top W^\\top W m} - - + """ """ smoothModel = True #: SMOOTH and SMOOTH_MOD_DIF options alpha_s = Utils.dependentProperty('_alpha_s', 1e-6, ['_W', '_Ws'], "Smallness weight") @@ -311,7 +232,7 @@ class Tikhonov(BaseRegularization): if self.smoothModel == True: mD1 = self.mapping.deriv(m) mD2 = self.mapping.deriv(m - self.mref) - r1 = self.Wsmooth * ( self.mapping * (m)) + r1 = self.Wsmooth * ( self.mapping * (m)) r2 = self.Ws * ( self.mapping * (m - self.mref) ) out1 = mD1.T * ( self.Wsmooth.T * r1 ) out2 = mD2.T * ( self.Ws.T * r2 ) diff --git a/docs/InversionWorkflow-PreSimPEG.png b/docs/InversionWorkflow-PreSimPEG.png new file mode 100644 index 0000000000000000000000000000000000000000..2396da691b2bf1c130e2451e50da5c4f6ea17630 GIT binary patch literal 50417 zcmdSB2UJsA*Dj0)4xx;x;QWZri+I}*`3;{W0rlB; zAp+{JMyenFe12@Q_=5NAoco+rGRMeQxahSD*WAYPaIi{{F@gKRI5{hC73FWSPVEw@@+HndJGGO3EL{F!PA+ACG|>{K@U(rtM|hU3=I&^R5; z5mal66Cz8H89`|4lBPYt;7)W45hnZkNXWX}zNR}4*;@vIpPT%)TFTOwVQ82UGAirl z@gJ*^6lLeFU<=S;G)t02)8EkgN?)(@=dg=yKw2p2x&qv7in)^je0*C+9~lh&%n7t4+TQ_@gsfpVk#&}}iJWf& z)*30{?bZS;t3>ZFr2P>hgusN1JoH$TDs`bhDv=`zPd&tXo!AS+qQ%_H`8D>H5;BAC(7iQciCt-CkHr?AEZT)dt zvM!^cz{4Yg?S8A-Tx++7qCgK}`|9woHg+=on<_g5om0gV;L@v{N!y#-I}DN%Rly-| zBgT3;?v2e63|v36eWKwzy~^Y7VVbg;)mg8itVMBZTd=XUzUM}BSApqq>kNA*EM`;H zs#Ygl3ZuKjn|hs68aDdzj}3yf__+=9|bP{&p#oo2IMv|M~6Mt8!b}Feqw5TV*L81`TeVm9 zJTn^wpzLKMS3mQAq#l|29tz%lk!Pm!ey9zbFIfVY|GB;OdF%79=P%a@{jbCU zxBsKKUpKZsKg|9U5X`dtCFY&&{$KA|bzS>UdfEMc{$F|xLQASmwQ2F~k?#!*Houq_ zYkX4gm5zjp#rQ{#2cT{DOZjB8s!S2mkr%zDvQHI2)8DK1js>94#rSW1etc2Il3VXu zO3U)V>z-0WW6`TsAT-x zMOzvLq4GdEm>+`voR6alB~QamK=|&1gts@2nPAHk7#j9)wDobkzpdt&Z%r!oagT!o z@P>z(e~mnco74$8xM%y;dsLcqx4&CO<<= zI|Lt13v8rgkKdQ52kmOW`~YbFw_Lwpat{sSlegeQ6gc+-I`#z0tG)v0aEZ}-k8j#} zfGvamekgoD^gWRRr;D(KFo`cGnlyRqh{-RfuJmij8Ei8~l+r!N{7Za_g4(wYt1@u% zMlxK&GmKJL6h))Sd1Of1QDih&4XZM$_xbI#B5r5Euqt6%ru;(iTQZu$^6yd#1+U*+ z<6XbGYeVJ-glx;a-dyO2#~D5e!dvOl;QSz#sgs1OLv{c?2v2TaJA_Zgh>?O+>pwjh zktS>8-W4pYNwKNxT(0_pYVL6yuOnApAn6?-?2cx?6b&%?eB9P&g=~?c!+tdh3NX-N z)(v{Akwv6M*yM?`T(XWNSL`CQ=?#s_0)MH>uwka+cCKz&)kdC)I3Y+1UU3u`S_$-c zv8gGBi1jH;pUzI2mT4o$DWz{zUNmch7;F!xDS0mW^j+0C5o8W;H=m8oIgA;8X#seO z8oV?F1x$wL@I$`)*Ke{cldGb8_tlKt0?DE_Mg3w$e9o|#y3NeYFzmCxF!u1_TbMeJ zl-@ao?PO&^K%UF8B#Y&}WGMh0Pmo(X(U7FOLruOT8w@K#G?`fwGOvK3za~q$QNC4) z5w))#l*gPIXA7)xPX7u!r3+gX_h3ao{r^KrXt&4O$3Nq9^yIgZyhpoK?nHm9O{eABv`p3=@W8yQ!3FC+e& zWorJm3_b$vi66bJ9~@@-knDDp980&FE9a_8l z1rKzV7h2tf?%1BYqFFWh?eWCEP4|O$zJK$f=kAd6wJij@M37)r+qd0yXs#Ow+ig02 zbw@<^f`usZtSxI<`SzSCSblRoPl}rddX@Tpio!M+>TmCmDA4=0yoeKiUVIy`Vy?+h zl6|FVNw!hY@5`v3_Pp}++Ru5wE7#^ZV$Q3@{qaV# zC?KpcdX=T`tj-9xuJFl1TGczabXXT8*3@>*I0O~ZLaTba&fUMUvZ@YmUomr>>0(;A zIRLw8(1)gH4HEvMb>m)Aw!W1fE5I7|ARe%sywqN~io0%VQum;O(&+8UJ$=PV)^%9e|+KoaXaR5 zU+rm;UgA3i2MWg=yir>%j%DeP@XN{e?eow57y%(Ze_45G*k$(JcdoUv_Y(>>}aKaA+~^yTJcqDZJtr62{|(aIP!tk@J)Cc8(uwIPK35Zcfiw3YMU7F z{$PzwS~z1GuCPF|%97C5876x3i+qnKW=HT7vxj6eqe$e!L>b%;qF>Cc?j}ixtPpLD zRm;uR?M74tI5rZl#I$}gj69mvaLY;JtAEkG^*#z&6BXNtA!cZ@Wp2$KQO7yx&saNlv%<9Z=R(1*CzVl9ckHM|6m+Mc ze7-$ut;z)mn|5OlF2E`H9#Yri7URsV?a33RyU1bJ3wW+xbup;)HSs>Rb$@9vtwVEh z%DR+Kgdfs^>E>vMdZ!mpGp_3{E|q5;?mtSHWF%%adv|)(j&y(vGe1_|c>=`AF}`Ku zgu)|Y+dbh5XZ==J?ut9+!*TQRwinbVlk(}R7JIo=gs0^Z)3<_XW*}IBNtLzzffe5u z?S5jh;wqv#Mn|)*j#R!tGR=CHZsEbQAE2hAayScQjkTzbu0E*jUN=O{A!Vh%A^}akK2DDQtizWBltupn9O00S0 z2v<6d$7ZlTIad$Pw%@t3WVv9bG$PlrpJj^-1HWBWn1*ldRL55)z<6r#Bcg<1&wY=n zhMOxLT0DzI;qOkhlcV5reRCzun@M;B8Hv~orEQvl?!7no`6O9V&5^CF9_#aD;g|?{ z-JPb_TdIkf?*p-?P>pL0hp#XgXc-icC5fu)J#^Y$P^6bx77q2K*d(K#&4z&=X7_;p z0K(1mG4%kgcV#9vdq9$x^V z%lECFSyX#6EBy15z}fejmuFVSKX1#-U?n-Ts)s4F$;!S6a{)=zrsm|unLw)WmyIw5 zLaB#deR2|n-s9J2`nYTT!&}kfx8fI3d6-X5Cb7nEX6Vz}Nv<_pZrZslK3Zjin?OH( zZlZHWGUl*VPw?{5vql96PH{=AokOIv&39^KQ3Il5{jl6*0#R~W0~6cF*?S!W#R{6v z0~t#w__w}MqAy@0*U{MmP;nH9@Lj+{{KQ3azhDC#p@>Zk((J12qEn3JgcH=cFOP&eXtGPpaUSAum| zwBA>cmNdzjR&=B@Y&MzRs>=tp;RD;Q--PhhgQVPcv!d7rlUc#1s`C@tb8TjblO#Q& zV@CPjOM#Y4-piV}uX9u_fBY;|)xZu!Qd-xgVF6;xqSj9mC$F7I$ntJBYOf>QjJi4x3uZ%?C##lbrIGMNfb=7SS zE*Iv6l$t30oUxjg)-lR}Lnd{=%=N-pPD9mXhk|AW zyGM^4vPajC7Njh1$hl7-wLI?8G2DAqfe0Twv)Hmc7xE zqcyKbYl8krWR6Srj%4d5n;U#XxMgA*S z#CNEp2SdSb>nbm;A&CEl1}lUj3|9Y;%^*W$&s{jL;gaVge?GN1_?fE3QxQuY}C#_)^QIwza} z>x!HYl;zQLPFrFtX^hxDVt7V{P^pX5Od7=64H{XFni}r7^D28BC4Q<_RLFz0SkLP0 zJJSoTJvn3Z=|c86!xppU=1v? z=AJw@abgF(s^u9qC0afzf!?aJaMP90WnS)#@xM;OM7uwa?hsr>>;tsmfjXQ)sTCSe zw&#RQHRxJ$|H{*~w0)eBqb|-M_|5c`shEi?B$D!I__TgknQ7L}-1O!iVp=YRNZ9O= z)Nmk*5hjCdWYlkO`aM&;c73cCehAW%6$S?I);)FlR~>vI0B@wIs%XU)Krs@#X2x(;Kc1u0m_Xya0T$a@>Lp!%e0nlo( z-5slW&r55ezjfTxaX#*FC*}dqNTtSpV4A5yVgbM* zb9-Uz+Prg0c&#a3^?_*n1b7YJ zFZR?kd_ux(7gvD1DHIy=)I{K91|x>@Zo6k{jw0MQZ%}O`%m%kwH}khyiN=}3L0xr5 zpoyQ4-`6K^i4TCzOTzQ;+<~jYINE8gsqrA^LNEoktS06&A)BgF z-&ohwzN?vzTyDiQvz)(9pVnEn-Z(+&V-M+Q?%3+CoXP`MTA|qE>g>@jzu&6a)hDaS zW;Vu>t#0mU>%2oGnU=f>L3w5|DZ-5W#aupUG3o#zbT!?5j4%@ZGe-s$IC3$)sDzQX z2iP==3*==np3Z+|+kDf02>@S{ovW@pHT!plFvul&cEOIPfh0;n4|EE3kT5TUx-YSq zl0aq2M{MAx?BJS$tY?p#-{3PUfiReI5T9I_^!#l=Fey%nmU${1jPJb;oQ6z&XPGQn z;%?1U9KN&*wtNI2BJl@x>*T_1G&4^NN8S?@2Hst^hu3wgDq|HK)(+GsuSw!CD)nuQ zDoGS28VDT%VdRT6LE;g@q>T4+f{qX6s{}r);rM`_^7~zM&A9Sm=G$_FyXf;1F;bgb zFY1#Mx^4SC?;rQ-G}>b9gNlmAJP;5ZA&@yIGyyeT&ybR1r}Nike{ zDvXJIX_0-wcdz{QgMsn zI)^ajvq6y!CdMi=0td9M`B=}q)4tz16BBlbdm(*4Ybd16uU03<4rg6kk*VMSzx-qA zoTw4#FqV(CCpHtkQ#T(P4IrYYcj3XqJ(zTT+Uf>=#qR(?;m=>2%S&$5_Qy`N7`@qO zJ&!w1Oc~}BTyK&nF_wgR8+dSCpu?&u>CZ$XwLv3L+{}t0o(a9NCXJFuRY_D!n8KA; ziLINjd%s=K^8M?SB{s%N9_4p@zDL@o*GKB%@!cJ8tSA?bsH?n0*3YbSQ&cZW_-P)Q zH!LOCfr-{}AWCv;b3s~+=dG#&zJFG5$RCzVWcC9>TwwqkP_GhyXUcIvX2u zNcUaT-Pr^9@Z^)WH!um6f?B++0{?NO&*jx@UK_43uo|p7ZQ50P6$5(-#m8F=e82LP z96G|ePr?rrr*oKC@Ul{`$LLAZv-|f20h9OPwO+<{-LTAjGgWOPRu-@H(60-vNm=vQLD?@uj%53%LwqN&n0Q%G?@5wm2cFDE!hQxPPVu$@_ zC(}VGM|o7EkV&SC{;yS|3P}p0>|MU7{8NRrL+msB40Gr>Lsub@gJsjh&<*}tR370( z60G(X9iG6(4lj;gNtz^t{KR%3HT`gh&e+`AII)delSW*xy+$?PfKM4{S0$1jINw`m z^lA_4K?4bmyd-c&dbfTxlV ze=>?GwH0A%-H!bsbavh|(-e8V1n>|F&D<$NyH+p#^B6ZjblMb8T}_@*3GZ0C)CD>% zFK{onmD6CSTRREfk!=1?N77jTVPXi00{Yx>v2NxnBjkdfTCdn?6eVZtp75Ar6#pFj z4xCZH6r*zvHBj>)VOK#Ej$C-eK5*LgFA!(M*^EaMvSwsFoBJmTa6c7R`?&W*?Ks)S zvt;d*xwTtCEFWMR9>w0qC@a5}|4`?yq|`kqp0as%9+&_4)I5&%>8(wl`>my0UyXXo zCm70MUqzhNOLdn&SgvpECy#`;zujL${Ml5Qf#YM=gw<;|Ds|H~yT9do{u#?`WaaC^ z^80lr*vrLREj1mQ3ifUyg%->)=IRLG{6}-!9~kYl8Tr6EmQrf?i67 z=|ID!7601XYi2s7QthrZ?^GK#RzMG_4C-P9fQ%twq&=bF$A#iKgq}W0;mf=D<-|Uy z-Kn6mkIlh(SuAbkS3bJPoDBnunRD&>@N4=4U|eony(RAzoDgQl)|Vc}#<<#&ye4h7 ztcJdr$3{JVbn5m_U}sf<#<{d>GYW|5yQvNXRp)izPQ4FVK6!iRN~hY!A?q{HOwB;w z;L_Q1bpk9ew9T=VCw0`&hQ11u>zl5Ff|x3%Qc>^L2HCr^`5$J1)`m#l=1SMQP`C`3UI z%HyZfRIKtOM(MpVW@0}yTsp^JEIn?jW9RPn3E;r!nmYR;qQIV=sSiE$8xVJiJRgu%5bZOyy~>d^<50cpjguC`&5PSW!En zMqXsEFnOTUkpf#`R8PUH%zI`-vJiuFgBR5{?s@KmdIua1NzMWME+QPe#}8L8)#eEg zZW{>q^)3r2qC~#S{pk{~a28Wn!L2h{9n^J4;`U5v0sq=k?ip00udkXYtLRoesHD?{ z?->At#DQ zBNkf?w(BE@Ju}}nR6n>O*=Pw66|hrfzK)0vX0|5~sBGSKoz>kr z$43Qfh^T7ihwOC`f|Ay=WdmYG#~cq-Tu>DW>%R_)i!IX8Wj?I75YFAHnn)folVC(` zAzmjs5Bxi(dO8f8JvANIU z2e#PYKNbJoq%Q@biTDL6#P{~PTVk~v1r)-b`s7W?Bo+XDSUWOEGtCdr`Yp;00SB2< zg&r1BwC(HEZEYirt@?Wf2cJ*{2eo;AgP|ry31hvWs@&QrYQlP834@7Oi%YaG*cuJG zkbjd0>LI8q2uu5^a5n1O&yW&^^aERbC-?Zjs{xMy`&{FG4{U^eKwpzYgu6D6P4+{a zg=5En8Oy^Oif=2wpbPBcz@C!R53Wf~l+g+NzPt3KeTQUX1S|2QGVO){M&qN-hr8_@ zf8ALgaIgv{o_^H-1PlUnF?iVv&3=8FXRiN(eCUxNOEwBQpral?X6E9fLI8S0xF!& zm+vrP^7;Y0Hf9JhALreD}|aK(?y~(65!#x2G@6~z9`LYU;L|YouJe)g=uS-l0u^^AfHp| zFtHZ^GP5=r24<@DP7Q_Pa-nx?-<-B}?^<=5TW-9H>2l1-(PKF1>Z(g{Pk7BB)YpgQ zM$_=A*ZI>UMSp10d7w@9FT~QMDDc?Gn6{{VT{Ra_oQ7=RfVnAg-nnx?!2wv5r+eJ_ zl)S%eU2>$!m`(lGv14O z({i-OZd5y*4N^Q737sfVs;eYvx~YV!t7yceNB~gJfZWw6E6T=3c20Cq&PEHsKy#m? zyZZ`M-R-_+%A@Q8@~Qe*7yTZm66xzl_`RVyZOJ_6?r3)LgXrDQOH6W&v zahLew3*Ckv&;QdZhSSIQhkcF6y3I|}6TU`b#a7d|W`5teSXUWYvW0}=#Klal_q&tF zYr|FF>akpyrTqzQCzcj(aON9EmHig;xZ>I3J|q4$v5Pp8Y2jdmOS-!4RrhhCA!rmD|rXg_W9}J@5_o`Jf zAikU^X1J=|))9&=uP|!6I+Ag7h`Cw9*!Ne2GZ@|;21d5OgZ>z>(-z{Y-7)jh1U<1% zGa^~<3-QbmwqQQ-3Z0lRQD@8XZ9bS%gIE&@HpXOq#ag4bTXlZsg<&I-*=wgzYG46j z!uJ^6?LW_rGDW!kgF)+~Mxw}rO-V%DZHR^zIAXGQo;+a z1{3?CIhWiX(CCDN;rf;{yoX}Gb;Tw!8uYDa*6&|8><6%D^{KcQ7N$c zXQS=9(*?A31`3$UmDpp zG0qcr5C$vhnO*VRr7{xaREdGDGgzsJGfQvAw~suJZP;d9-O>J817S>|WwLY@hh3Jo zHaqI%w{9+tSVU3;^G`{+?Vi>YLC>wf*Qu0KR~+yzdf-+_r+#y#!!QM8?#&(`j6VR=lktcPaqDr5KtrQKY}Q z6cLCMkGThQ_+uYs<(!ye+ecpDoG&rY2P}s7%!?ct0nTF&8-aYDU$T^%9|4^HeMZZHTE9vB%_IoqU?IvhnLOMcNy}GmX)Sc91(LFrsD7H&?_!~q4 z*Z{%IaKMZ}ZUv!NkoD&$5>D9S7l^eUAJVg(SJzpg;JH%52Vy0Rx0mtzSH(WuT*u zcghUUJceI{v{Wesv?OnsQ7bLAblphy}x0TS<~WJsQb8uw`_cnxAdK|DSDp zF1Dgrg&jSPGgl4mj3WP6tf2q_|{MQ_uB&dw;tF0J#4(-J<_xC}lqXYX)$810js}%UEwj z+|^f((*4P<8^vYP{V%RGu~r9fr7qlB!sYgT@}YQIh_HM0kp-0v2}-tJ?D3=0OVYQ| z1@wIMG0daD)af<7wMr625!0o#GLb(-c;lR(JtzA=_i+2{-+R#|AVB&>TLg|OL5iEd z_2K%5aaaP-6wlhqZ{yM=lYVXN|63Hsw@(!uG{jCExu!Py{vhohz^C+89hHupNJq%N zU5xhAm=}+}ZyeuvE>rZr*xZqZQURjIHLqF{CM>S1Q`@`CJpQGOj(=1B|AmnGiw^n^ ztMr|1RCKT2{{Nz<{&zmDG+|ky?z4(-KCUXu1f?+y}!t?fRuxW2*3HTQ#||rVa$4mhJt_7Q`G<- z@c%=xvJ3Gx#sGWvx5RI|`f&U=S}nEjAHplBwv)Zoo0-wTZ}D$b;;i{qds~2Yx~!o0 zZ&xdMpveKqB?~JCt#FqGd=ckOL2l_FSp`Uz#f~+bCc&0p`$Z|9xPYwk)%DDLxn4IM zL)3dW}g58zT1ZpZO3f^JsxUH=&@8P&7gHKK$*Y*SY_!NAIz`;@G=8J~O zH7Vcyg9DWY6cTg@bqW2!p>&ypqdW{K?l{1~;V${F&&!;9IWAlAaQySx!LbKu@L!Mr z-!$vs=mZ*+hy9!6eu>T5-Kk&f;Oqu_8zWyK7TkZ-` z1bODOYId{Eu`NdReVyz^2Cv*ebjicdx*C{oE%@Dx#tol2T^iJjME(}9p>Dt z!lCH;&2(?y7E(xpEtv`pT;T|q5DpfbddxsUEa&CVKHGbMi>_L@HojK<@W8bI=#`^`8E{7*~KAjchV zmxqKax)Ya+{Qa8y z_NciT8_TvYwFQ*5J1xXAC5c#*kfmZJ(k;k5@bu3e=zUe#6I1)mFDpIrCPJyOK33LZ%Ye7$^Qzxt$qo zyjM*|mVO`eJew}&doU>&@q_X?`uO3QnfpY4O;?^wZ#eNCOB1>N+e4U}0{xmoWQSq8XC{%sC~x z7s4oq-gc#}r~8@hjWPVpY9&!O6x>_gVwHz=T(zd3eI_3^#A8CQU-XmMP$+XD4gnqASY zfTcs|M^E`=Nu-X593ZSlzJlaH0^4%yJkjqQyQiwuCzosY2ZvPVPF0aUu~WrOv7Lvs zKSwXU!3YEmeDcVQQN`veOv7ev8@+L38g0ksCdOaQX?T#;?qR17H1biy)@54tq;1X4 za6JB_L4v4r>{=$o0Me43*seU{{X}jRb1Tm?YGb(LO1s#&l`Of`OvwenkQ#5NvzS@P zoZF@!J9=i@NR!Jf*eKjXwDxYvwkv5)V8|_AWc6 znb&Z64C;h?v~3L1d`d5gbt~3=IspKB3lqTr3tSs^h z2bXF?FZU?DpjQIO??M2EsZdhW$0>5r?{l4?qn1;$nrO+SApqKw8dO9PkCI{B#RR%}@cT zwg6aAg$N>8%T?3_%$XwGo`~}WcT<$H$mF4y9zsJ{1+H+0>X*M?cm`sy`hLR-G3iT^ z)zRVJ%YhI71OMV%NBVmoSPnD@KoFOVQ=ezxt6S~g)F&4J2kR5Fu;aim3euo;d}VJV zN;NHX86ZVS=A2{q;w02q$4892Gz7>;^5g^~RPW)0Av;2Z%RB1^mFM! zkd~?UD@h?KBK-7Vk!s`>YeO;WMijfmg5dU{y*wJee2EW7%M%rxe$xD8Ir)^Q(LK;g z;gsU$vGEzs`ee;>?zM+LxGzqCTHw4j+#cF3Q!gzXr#fgR&5m|I*UtdQ02Bp$viBmT zOqLW3=YbfAAKB6+UWzArRm-EEy>|a|R~NvMokpeTM|TGF+<=|zWF*D};+{+Ty~QXQ zOx*1c4sHNy0i8P`MHoHRglTlGFxoxHGqNNHF~8o>QI|inwQoNZ0P<{~G*4-%oIt&- z^n}YiPp?W094gNB?Qf35biB+mVwn{wHfR=$*@0F*4kCQgN2tl>eXHVvORT6Yq{u_k z#PABK0b#aw0`+WcSir;h4~_!_gPWkkS{KaQNHKJzO|865&SRC<=7{%)0}-JL(`KEW z?D**kL+ZJiK3hI8c4MorV<$n;$nn%Fruv=)SSdLXND2OwE}+x}21-=Shx%$+OKY!a zW91F!?E6`Ji@fBFYA>E4pFM()lyVl&I5KwaZRMu!J*4Zk5%;56EoF8hh-7Vv$}HHm zmWU46-DZ|cP%JlWr{_Hm8W13#P}%ULIQq*DFZ5?+Scl-!$ost<099;50iXsub|fqK z>#mr}*f}m+>)yEN)ROFT?RxnI9h2*U9zQ7QxAxTUa&5L~@K7!iaBO6_UEmT}S8>6! z&lEkbj_fND82n{8&J~4bS;tkJ)dwg>RuvQn?m6MpIhv}o@k9+2I9r0 z)jrnHYsB4^PoH9079h@G2KV2iYWTM5$os+%-qZuRf%(ZceB9Fvwe$u%^%+AaR$uxG z=^D0G>|r%Fe_=WXGGKSk8{CR-C{YPjyMXSxC})n5r~5Epk~GK)SUGeQovK#&HS5cP zVW6L{_CbFha36flVF~Bk9jO<xvVS8=|v9@zZ;#XFZyKG_Ax3i5=(Yln<$e{1w&FQg~ z?6Dcc&75B;#6}a6CBJih?cJ}WM4r6&qCu_B=wP*@<6WSbGJYw^RfR3__ucDv#*bbM zVjB2?R+5mGWo74or6#-Wq|TzM*3fCdJuA@4a;A;xzv?jKrOzR~<|HlwWqiK>N&d?O5SPJ;zt0I?N2t7F*cdGD_fbx zHdyq;?!*ywsR~-FM#usX;FnG|t-0<2>8AxC<80}7tHfMNEqg%_d5`3EXIE?)aA{Yc zmcKwND)JM*DrmjC?Po;G0|5t=j;uprq=8O0mDta0m+ls9D26~<%9UYzRMm1>Z_OgW zq>iUtU#lihuewrz{r!8iIf(P?hXVu-g}G2L>Y0MWAr(tt-Nju6E*AoIHe3LlKI{|* z<}ly|E|(dC@E{)OS+DG)KnrPLdAF!T_@KZZ_y3U~g;OF$3S3WbN}~2W?A-@_sCVh# zwfl;4D+j8b&xQey+?PTg0uTBp(4DaY$F-a(D!2-SVMej4{y~E^Tqw z0_}6{L3B0!Em>O7ziBT0QwortRh5|vS!tJ9!fZY3D~l3z-!53M(QTHr3NGQ}bpN)= zueT{|~?eht`NF%BRgIRbcboa7uL7$`E=*3buz(bAWT>@8)0)2fsEpiW+L zG)C#$l%?t~ce)$KkF?N%YSklK7Jh^s8$%4I)TH&vU!}UqPX$)y-W&IswS6o$1aMsa zG5;TLbXJ_u7mo4w&S^|JenwEAjys%hK8$lOiuST>zNTeec05D09%SjprE};}oOqMt z()o^nyAzC#?GSuly7y47mhbo`BgN&hT*`NZtigz$3@YX3TtxRrtu*21Gxeijt?CQ8 z?a_(`sz2caw(uXHU z6Lw3LMh$Z+`Qa|dT{Mf;*=w~AZZ^NRt$CnydExHLmSQWp2%sVE?|~`PJh5g*GW`6s z3cY~Mt*b7>9u~ew>NL1+8Rh#fD$6p@4c!=mJ^Aw-_yPZYbzP0BbCc86ZF5t`) za&CEYFC&(^LhcGmlPF0i1O^(z*Yy?NefD_+a3OuRFI`1;FmCck&JAT%*3*aL#@UPS zviQC5XSJ8i^L@j8UMg?_Idu3bKByfx13t?Rn}hbl@7~1l?xnUZVaIpKX5`AdVG{P- zTUVAUBPgF;A?3C|gL+_nNhULT3#1qdTnvm#!Dz?LO&Rn4CBy|oBr8n2H`gNe)9TC! zmnT<20QrJ{4ksre0Mwrv&Xvv8jQZ~Nkx>(?r3q^nq)*viya-?93|6ZD$+I%>#$U z-lNn@MpdnkR7gy3kuleNG!vrEmF6e6%UlWt3*$tcL8QA)ZL1Wj=h{955ctbZo9Ih1 zZua~v(x7hor4)#*_?(}|`JOhC(J2};R`%TA^F+vMnsy&wn_$sUixE!nxyw}2o z5Taf=lNq*tCBe(^5JA)yWEwNHc79%fI#&WK=209h{!!SjV;k9?zOS|NTO#MDh{V9) z<9-psm9y##3{g6LIDTC16@Bzh__IHxukdmUPTUfHDWs!t3(>endXu| z{AO*N-eSzF#H!_yZR7H`mBPY2*u+39XLX72kxH{3ahf8k5z^LEuC48_^may%4@!k^ z+;ytUhtdF=@gSw!Ilxj`RZy6qDQX9Y@dRVI@+-qgJ&p@v54BFA#+>StVQu|4h^Qi} zXOh)A!?edA>!!Ni5;pS9OLIY!Cz$xNx)DQSFfF?-UX${*3{{qWVBi#&cIkP?A zE6t8!^83gZSAIC?N^L{>H5Pi&lD#Ao$=y=!v%P|M*8t=G}l#qn|{LM4qQ; zwmrb2+PMqsR4BE!KnE(dVC$E+8exVLk*jkWa$=ZFF&XRB8 zy|K53whE|g8rQ65TytM@Vn!QtRzrn;4Y7YGRl&+&g7RTx5IWxJDl$UrH_%xOpq@ZU116d1zQ z+e)&(glKvW@!b}@Kf+Qzy0F82I-(-cjc?hyyq3UV49p+rgYt$b*U^;rUH|YNV^z3 z^a<0GDU+acPt#eAK`!b&vs(lQ#5E`dhac^l$APV{r%S% zLEU>sHI=>X!#a$BbVr3q)p0B+Rge-O2sknbg3>$2D7{KA2`WvcIZBfj8KrlDPy+}` zR7!vl0tAQJv-iF4`?{~|+G9SAU(!Fq zJY0?B>Uzk#K$?ksdn0aK|%*oLsZmm^rvi`#fRx@Jdmw*n)0uki7@rC3;ZJz1BcCatVl&= zdM{tX$5CwiZpn+nNamG-oDl_O-RrV>H<1rUI+4+eff_VqX5Wm$)`y?D|CSO(D*{%u zW#`m*!O%(5lnblxKUCjVwx-kvVC2mc3)UqPGZZ>nykb_!-jc~92J(>x;e^#zd0C2v zG`we%`|!=s8A4@kg<;&Ot`vSky=**ag=gtviH@zb^eLMcgsP%E8`i zdk>$t@48^0>0RG)ic?#5-ez7BaW*%64#=Y{OTHC;NljyV28pB7!O}I3iJ}yk=gL>q zwiGTb4#4q&S$er9-U5EGVvd*aj?x;vXoF5BmI4Al-Qfs6 z#M(nF-vo!LcEH60mw;-JWJfE$1){@H3w_N|*ip7VXL@3#l|*8aT;R90ChDQJx9%+t zrL)U72STpNUi9e{7!Mf%cg3z;+2Uibb-?!Ju2l8#RI%Mvlvy&2cu;e zjPA`FdjeMU+rwG}xRE($2Sr0SZtc>S#MpHcO{Y(nHTx12d{#B?RYkV(*sUoxEUSzb zP?5;gDfdn$)=NE3G6*olc8mze1Nx#jrTjQ^thx&|(h#^rr35$8xWe6IMG+l$PF>SH zRduUX0&eGJOMk$6xA3(p+zp10-8>u-$B&Q;idc!@VM$&cA~g1+JOD5B@5u*(*U!9e zE)`M9Bd5cJHupqTZvt9n?fzfpg3p8N^8M}rn88(j6p&n1E z$nBxd<)J%H#&cbBL`q+xVnVTAMayoz-a4_C3}>qO1X};llPEI$R3DICaUnftvvut5^A!g_cR;I|IIp&Um zqf69fFfF-3U%mq(Fi{+E1*QdGuM-b)x`eWxHGMm657`aD-zf+^zaf7XCNUKm(q zWila;d@SIf<_`EV5fN+%r&C~P;ahLP%L&icSt@+0X$Axf&E(jvap%BRaTf?7@G6a2 z;y4>?zll5RUFt<+qdIqo>W@?C+|9B4h{eLlR4YEB6_ou4*^eF7XBKzmKqh%mgdc(@ zaMmgmc)uCuU=B}xp{5DAEgd46{3<&8ya|+%0Rbb3xXq0hIcu)cvi<~36n}5Bt)xEW z_$MjZ>D1HOc4^E0^Qf`GiGIy0Kgk+zRCFK`!m%~!Rz$+*Z7WW%OW)oZeP2F4fy0c| zP15TlNcc-n)&GDTzpBN)T-jMr>P8DxnY(@dpJ^HZ3PGhPIj6hN)3NroX=a*H@WHhE zvLN|M^rvYpm$;1dtsIhBXOL{*4H3IZ(p8^)GwF+82rUze@*>X{Mf6qr0s}IX81yl>frmBW2C@JghL8#Ul(w>3u|o4 zm^zH=lu0Y^%e<_NefV%V+d)-#{bYGO5y~$SNDMeh%deHA$6-x6zOIKBW+c-jXng-v zn;s0K0_T=X7f)y7{jWQ90l#z^O@rF{@Lf}G#G|8U5=m|ah_mCVsH-zK=&I?&jNTcH) zdi^b4I&@(U6y=BS3gba)c;M)E$hc440Dw<2xrWhy8@e6J&IY9}0KGKR0gndwx&4p9 zJTS*GqYfC`_*_ixr2kp$vz+3Ho1^D5(XZFSGAj3wmt{$xj%K9CyE%I2JX&7fF%CVB z60Bf&7usj8?x-z!oulIoOPtsK2UwLdBE5I@`sj!>FF%@M6zTMOaK>p|8s9mr1*GPiD61pPgNvGJ)N4%irwjE`Q!7v{?|3fL&MXcjSrq# zVOvI|$qQOQ%5?3#qt0=T*ZyWryW5Q$fe?RrS<=ke?DSM+`79zWo#4SNh_DMkwsYod z#3g@Lks#bCocmJ3>$?CvozfknXWnda_gVN^hNOT?-kxTQh&s0Uwr@Y1iw!w96BU4J z{d3l1WSb+~u%HnL+w8hA!Ub+`wfy)gXJ2agsB#57k9^0}Qipd_guBG!Fh8c=9pO$F zum(eCx!D@F5_-k6jnm}NY### z>K%{#zZ{(>b)9CpEe0>tUpXnZ{LE`h(y#O3?TPOKzAZPMN8SY~ZbYhUNNpzh3=Dni zY3p-=!rIHu7qL)cbvV?gSYB3;sVaYl^N#UFQm3;PCen9J% zP*7a|PB}NC>$jDFdef+BZ~eIl06EVahS8S~=X8ubB?HAp*28VdOrN^fhJmZtDK_JD zd80q7G-EGlmF;JnY>IfFJxuz+N^c3X4g8YW64sO92=VsJsdLw=RP8a8L3gZtc&sWm zSu^?zY>2V>cE^5~*%^E2QX~#ge;>?S-H9{NWqRq=spXW%ZYNddcyPBYzK31+RVsp6 ziea*XWzXP>OE~`QW?hYEHbz*L(3wbxs=Ytk=p5vm8)9W)2nRto2W^+wl}6 zWz^tcWK#TRZ+24@9ciy`?yIpxgfeKjB#5h|H9mrlC_)X1^M0cMc(_pX0T7!Xj_GRz$JrtOE{ zeWsZCBin3ku~}KJQ`!U;CBH93GV=Safj2E^7^`Tene=>{Vzlq*1_V$pO~oncW=@x% zyk!3FvhO{g+_|2|oh2Oq2#$3%uQ*AW5bkQZSg>AHR4;Da;=1rH@+Lj>Wou#fezTsp zs>pNbgb^dGa4Sjb_x7rnt#kg>;;R%ZjRI{W>SF_VY7t29gc$rJrn`>NS8?05NBnwUW+^ z{J-GJr1!g0&q)=+I!4Imfz-eJHLQS~j3d_v_vLX{&aa-<-V4`!tR!YI-}u`5*W_a9HDi$voxQPvjPkrYk@fJ2S}^l=FDp|D z_ZzGQ{W+dA%SA1|mDYq>M2F0YL2uCbX;e$aHodyDx~we&rr2zwhn@9BOiU?%;K};Y znomJW+Hd5vMOc)F-C?0KeCHBgcW?&Ci}#hs=%4J$1`=gec@>#%!n9f@lM&*088`Gb zs(ubJW;vp97o`dNc)PLX$x1knncNbhQ7+&AI;s4o&mg5z`R6m;Zj!1cc$xeMa&zl? zP-g%Nu&rfq&H(5A?(FB-EV5(evgf(&2pThBa`_iy_n}Kzk82QrHDN;IRgwBxUW6#} z)ID6Y@5l9k5qMAWU!85^z6wp&F>+#gtmg?X#e`<_7{y!sQ%wGxvB6id{ohXm3z6#G zz!yOeH+?iGqIPS3@TuSyz)LXPY1564Rt`-Ldg zY9IM^|BBku+iHI;V$_hFaAdP+rj$med>ab+2fQcjSP0*%cDZ~7_d4qpkoa$>4?1=S z=Ufsk@;dXoTWe99&I&&_kM2N5n>L7)#1}dw;$PI7K~qQ7fXvKs>ETdv?PTzff1_+! zfG2MjM+Zg+Ze%9GJg7~jJ+3)%FEa-P$8hJ*B)B!zF&(g(Y!d-^~iYYbrmzcN7EALe)64X+`vkV4=-QXS@Ch0B(Nj` zXcCvS#<<|%LlX68FR9ZBHsV**wk?RuZxrs209prR_vezj*mh@o6Eo2hUE|_#GGrrU zsP0%nVC7T=f0ct{@=J-SwEGGsK3=(f3XJV`c@Hc*|oB zE*^0;@F}mri7m4UW;R(r-;78sU$Ha{lT>S|Bu17j4lPvpqmU&fCM>bp;bBhDHmwWL8CDsxY%R0`Jn{_aA%Y>D|&ql*x}dniybYgh|V6LCH}tPzd99d9mJn0eJ67P*cxvj;vSfr4?isN`G0< zTr1G=Wwd13yy-sy`Cjw;Y}{6RFh8QAi*26To5s9#bU7=Q5qi=%DAV-jB)Q|w3FE*C zD~HaEa0yO`JQv>zz)Ic`QecVS)?XT%g=w{WOgdLevqkp~V6TD4-r_Hkn_j7YQ8PLx|gST=P#ONd+)KsfmgQF2i!C8*?r6cpy3CkMe zy^8^`EY4i{9nWxfM~T;C9b24+tkjD87%S>bXGZtvUh_n?W2LZUH=ZG-l3>8tdSh~T zkiG-!1ah0a;A7;**v&O;RT+T?F?i$xP3N9m4z!>C*PBwC&vpG(KH8ri<_l+gDQoU$ z9RM;M$R0+LL`Arnc-K3s6)LRHvYf*Sscl}fncGGE27+;pZ@}`-O-f{A3fMk&R@C}_i$ojVDOoY)9}OKum2eW8Yk&O& zG=<%f@o7Z8DK+q-Vg2 zzg?TI^v0>@r<5E4#*TjHHTZejZ=}wYp=!2xlJS&Wj9``xw!A(XrP>AjU;3NR_m_?} z^+ivXp_3&zqET?8^qqN;cll05rDn6UVoyq?_zxSJ39S_f-O%dg6j>lm%JZL@GMdln zx*gf#0jW6$nu^&3fel@pz=~V%`DLb7np3TIO#5Y;m`J9qkdo@d-k{hDU=>*v$FC-j>_neX-^(9JYjCwCfX>00?LVVZp9c!BhQB}v` znbdf%Zxd6OLf?w1lKNWsODg9G{{6Mt-*;bVc0b7wsbh{vYwmjqtCaBzL0WpCMU~Ux z*dAy*qyIrECNWu*a|2()WDAAWlgrWr6hAeOuA^~%YsP%SgW*H+kmi)~?)ozSu@f*& zIZs-tryZIP63h1s@b=f){)IH-C#)H9Ioc02BBF-%?I1NTVxCj(g-4tStLN4(I%4IO zR^zoVObflhTT~L1jepui=@)Jt8tdo-YyXw+MoR70{kA4`zF9w&v{y zkumv_X02&(LapePdM}{)*+O18Lm>$6QsbOhyL2Y0Xm;%56-eV&{O1hG9>|(&2 z_e~JGXh_4VAJQA%x3tK=pq5BKy?Q<3N0$E?%GBNNKoSGtiz4k|R@{#^H3FKvzSz0A+`M~e`yIw)@JPNY=kB=7 z$K{@S_UYKC`K4XyV;!Zob|Gd(r3H^%6~(cfo$Rr>&|-Kbk$f@9fH3)Z(rx}-tEakL zjx)qxdZXf0&}|m1f$~e2ImHAm_9P}iv)LXP@+e1WM~LY_%(g|_D)*l5OT_}pXe>22 z!|-PC3(@ll+bd$6;)VsD_ThtfyBaJ&jF|c;e9y%V-ad!V>3ENOAYFm$fut)+r7K3> zBsYjRQ5F!QGKp0=`Ce#=Z;eW=q6ZVKujJa>%rBNPZ5D5uP|t}kbmL7FW&W5!s)e1I zETJObR!MBT-7L)uhWavEwMC!A1dm<`rh2G!4iHl0a1Sq3;F1+aV!E?BGA@j&Xq~!} zV1plK7}zrt8!Dugo3!pjj=zT@#f)7rCr&4v(pNx?Ujj?!&?Cg)=+ZUN|8~1XscC=r z-B?e5H<0hjAZt#^y&~qV$l@)=UePA=M2LA!Y})k0l1TYnuzlkvSzm#%6^}LQ1g1Hl zw*^#%J4?mqC@SBquY978ReVVB^8iv=Mb$Ch(bXg0c7?jKdEG1>ie-W#lHD=0y(2bd z(C?S)aA}>ZHsQpFrMI1HFxmM_SnuH{Pe1h|hbK+D{Rx}I-mbQ}?riB@*~mR-ds2zL zU~lmE%S0D4U%$KM?W@P#&Sv*5c(kj-(h~ga$-+I5`XFGOclRw;LBi=!pCG_`L~;}g z?r3HBB`gEa#G8qm_Q8Odqz!09_5mFk#wB;1?|3X2L6nXpZjJ~3=M%^Q%##TEi5%^< zfT`p=0AQY|<|#ZcuJ9qXgY*;tBz<_r1Aydr%`||P`hyGlqLK^%EFw2ueI3&I`fS4C zN9+DZKr-WdEE#|*eSl*7+JC!B6DA|2OOI&AcCKAicIpjRO>^_ps=zajVJS-)l>OSC zXl?lbhWe#TpyFRZ3I#L?8zxQ;J>aex0^2DG{5--@D-cU}Y z()?c6M_BmYN&X+dK;5jQede?{mM74$Bz%G**CM9{lO0U0mCF5roTc8~oywTpuho)U zqBf?@StTROwIYL~8GlatH&WMCr`MS`Zi^VMVkI9$vTl=ylc(^d?+ce>c|-r#Gx?nr zxFR_HrYZA`k{H)F4`3ppa&e*v8{~7HWBSf13$^|Y7}+lzAEvSMOFi9qmuZBabBf3B z3x_@a(!))oDtBfq+mao7V1lJ}UMIVJ^S~oyM5;M^tEObFHs7!7WG*Vd?#94>2~<@* zLT-^HJvetL>72`5dtR3c0M$W5rMO-*ZFAQ(VRP&hpYDdvjP+^KqbYr!UmcU&kj6?0 z#h3*b6<^yVI+k)9_y)=?f!DUq+|*l_8ElE5``hQ7?}lGda$s`pR!F5@`mGedGLcC8 z%ZVG@ZsEOLHblL-Xl2s-7MF$O~w1Yu#Pz`5mSO1zTm9NSq9bt}E3r93b!Yw>Qg9v9YeZ1F9RK(6W# zZWCB9p8PGM6pM>%z~(E=2Ju-f(waoRnhlVqsr7c7NZU$N2*C$qR6Hr*zd2|`J1al#xY6zJJiV%g+$_-I%Q1)ei}taMtPav% zu)-gaV;);rOhyyblXp<_yYpm!F%qh zd`2FpMQX^Y2A1p>VR4QsPXV@xong<_T$}M1KW#u1uw1eeWI?*9%Ab1!jmuZ(4aQ}bGo=hI!@SZa1S|%8?RIolkfz zh_x}2P6-nV%lqaz#b$P{nxzZZTsvP^Ue_P7Gn`|#n*=DQJn7Re3tvwiML6rOf1;P- zx7oe{&fig*j#t?i{bfPDLQdb3s0I`A4>oF-?A#qpaKtG%Yf0*@*~Dp6DT}OoN_H#Q zkcg62y3+$(J$8xZsbrUqc`2nmHyu1HH3gh6xav?iM@-wM2V=-mzrJH&v{`#vF|;vH z&Z&zL_L68;x9p?GlKyrY?5O~gdXk3&LV&*_3mLp)HW#Pts$?6DH|O?T&odQ^(?u zgStSbuouQyt$Kj0cmTH`x8iB@Uaqi-6;rs~oSsim|8Jcc8#aa8W8{CabEL_E-+n4_onEyU*w z4>j?eS}gpTa#Y`>IpWW9++0VndmAlpD0$)*yr+DLPN%XgX)G<4fSq*2h1Rm=%HX;t zyS_!&w)}UbO6NePIxW5BIV~m591jInIMB?a*wLq4s|_zn4E%^B(B{cv2BJd7$GUeo zwe{8mJFbC@39dXCC}TE2IoTy%Bic0a7(SO0?9g=A9qMqQZ3RaKhCefD#!E8-93;R` z$iKa0%BL0dUVxwgH)^U{Wv0#K-<>kclS~uSt*(F@L6P&uWJP&#wBnTth4bjNwo~=_ zjzK(!O_9hT(J?zaiJ7QW6U9el?%tXvZo21#*(_weG4+T^GT}*(G?kLu&L;Iwpljs|{^+4<|NlquAIX8j}&t>aE zl)NP7U&qpyc4CU>z*iSc9iyp*-wW>M2Nbq%%X~CQ);`*+J@h>g970vF(-$EYRtOEAUT2jHHO)ST~ble)oGs`KSo9Scgna=3ej zg0m9uV_h@?KL=yKfhSp7+KMwti53gWB@QhetfCV&=zh!=vmp zhE4aAhS4+umgBJc{t1r6!6VHT#N5cXb19JD5)6X%FUP!Ix5+S-s?9gU zZD4)1hwn6TujXvg3q}K-bnAJOe@%EDE3m;x%KLX2^7$Lb|9OA^IZ*rVZ&Z@84g&aJJfg9@P-j@o3L$_;Gg5Z2$|?m0#`jB!}}Kw!{*yiiDZr zDo=8D)5X9o!e`SZI^x1@<~;NBUfH8pl}i+yVH*VxNE(^(d8$g(?L(~jcfiiS_YtuJ zlUgxgW{VcIx%+3F-}Z6`)Apw%(?XWb@NlNFtk`b}joHhT2)lJ&Kb5+2wv5_WpI~I6 z(61I`J3&MFILE5+n$6vkTQVneBZVj)9~6OYC?~Yve`@RMo0~Ih(WQBmi4?g9=-wTM z<)E8fWt{b7Domok0wDW1h1oE*urW6+>!zz63g>f-BZS5}r-y>Wj(-jQL(>5Aijr7i zAYFB^`Tac}oEoj^)I%OxDUob+N}~+-mq_*)o^!`7ts_5Hhur{pr#FL}%4g?%H-=xc z0fv_rcoE%&%l%aKEqu6Mak#l25mAejVr8< z=-H&2s zaI8hLR*BZW4hRxK(0;+4pB3>Yd7@3@W6-u{yFI;j+f8*J=!*7p3bnM3PAJe=i*P-P z@KzO9Y64(yg^7u18Y|#BnE8l?a;+JWtMWOV%|Zvj<{tGHp<0pn#SG2|PI@vpm_&UV zt;dy*i!HN!chf(!)lO&o%v&$3?v@7>K4r=#V-u3gPeSXQY8b%AIcqhPxK4M*W9_!c zM)v!=noN3iRHIPTOSW&sjZd$ZuF`EMwPoMh;&;axC6bibwcka^i)Xw@r$ubB=3>5u z?9J24l!3q8w$G`)4-(oL3Z9g%#2;dv_!^w;YKzXd7Hk8VD?he)kpXS`g{D~zE9k}q4MpkHdnAHtXr^i zRiiZmq%X?ch(1%UojVsPlRLkwrQCE*3D{-+xCriu+92=d0^p)k@yBcs5F$gUbk``o< zbmd#hIoZU8YYTm`x0FVL-oKc&*bUA^+VCh@)(9+=j!2hxkWKtXwV{9>{QkjY^5KtR z_VrRz^Gn^pZd-6vMe}Gc32#6;ZKz|(X!7vWC}kKGnid9rHK7^Rq@ZFa>mFo+zKVDW zhUSd%8H9Ocj!Fak4e+84Fo{PBH@J3EIx~d0R;Bx`OOITMjHcEgOBC`Jo_r)q>u<{p z_$a!%Liy){)KGJ8*^r{8xD}Bf<@lRBC!=2F_csd=cfqL?sQI8jXE#v9gzUkIS9?!c zXLE*M*c0YHXEvObNdX#)naO`) zG78b|LA_+(-6VH|On6OR$syd!b&ZPrR0U_zzu7r%XAzq^%^)#Xbi53ZQ}Kd*SGVIBzEK1}?Wlh`qB^qV?x2R<}6mjMVi z-+q+@50b5ZK%ddZ9dMCER;_u(ao>+yzDc#Vjygb(UkpuRuU@D%q8oX;gmVYX+42ircQqXy-j zeYoY1G2(fkVj;pG6jhqu*$4w)O)6UP4Op+zOrk_u6t9HT7UZMFc>T~TU9J6$w7H6p zR5UpOeXDb+O>Fh5e+hl};2nUUo}olVieIOAgc|eQpDdLVajMZdtCp#;p-qG-0vUPjHq__g9a2IUo$kZE_kn8dB!ti0_Vt#zA;f*H?Gq@jAZ z;;PA8X?k=L8qC7{u<(;%d5*1;@it;M3EktLhl7hv;+iL8uO0MRGAp_ea0ZgOSv8&% z*(@2ArhJWMxwR4|Aw`CK2y2m;3eUNUKCi&tdOW>ain)9PO-%(28gLS@@|e=#szXxL z@S@?qpW1{IX74H2t2l|_MoIB^PVr5WBZCz080|{=H4R!VDrrBme2VRj!#NFip9Dq@lW`2+b?_s>td zxK%s*xC_;-XwoLVG8U&I#(7+7ddItqvGqCzw$Lb8!w8eu$J&Z1L?nDLWzZ|Da|!az z^8&c?jGUu~lO z{aw_zMJ%iL2@=x8zJ2nBb^V2_8rO4b%e&Ve;V7RJnlvs6*qW>(hwCU!sXJx7XIl-7AaxFebJinb4cXNvK5Ks2+x*QVnZa;K?%ujX8&P&p za;_AT%xAWo%B=i7;4*A;yk5EkA~COLH67eFCKScGvvaa7Yna8?UeeT<#{V-@*QbD5 zxJBgKNdpUYP)ASL zu;&K?${TyfSmGb4mJ7D(^3=6bWYh65?Sgk+ZMNYQtfy4OMbB_Mr@|e@CBw}~eQb_F%%ljWxY8(#D&98NQHu=lp^B5s8syNHSXS=FhikD-Ly^706q zFN@RR!u6TXvMx)(x+(OF)>KU@O0!{c-mSokr`kElfORtka2cM%wihtbm zlsvBmHldl7`WB}}s|jwb)Vo2Kr7qAMGqUeOsX-Aex4iwvjJmAUG`zJ1zOshBri99M z={N<#HoV6TFd#&BSrd6ts>Wjc5+4GtH7Io`%zAWsn7ZE9mOa<|%NLiXcgEKV61ll2 z9A6nH7W;Iwx0s;unF2j}t55@36r<=r`k`il^k;A#Gh+P0Q|m8KNq=x=LFJEK4I5k? z1(o>)Dwi&rhF)A91|Vp$w@b|?X7C3zxB%px)f)X-b%z5M0=^i8mmPPdFICfM{iGG!%6PWRc#CUw`G&u%z_cIO8r%_5r)pZW>j^J)2- zPwbi-ws;&G<8IyeQ1!MtwLd<-tIWzw!m1{B+ViyyO%4g#^%LF3urul z@NeCd?-(H1yYS+gB5u&bmbd;i6oKuXO3HPvM)TW~+>w8(j)pPBey$JA=8sNy@BTx3 zJfhr-@}^Llk;T9JPWb#dAFeVhNLn0yB)bQPNyAGTBMay;*A|^G;_pr19c$8->or|l zY`7gvDK65b%_jV0%!|4OF2FdEPROb}^18UqFdSKN=+N~tgX=ox{)JVMrq+KN57;K{ z@7KX6(%x6CxplUd;O|ZL=$53ymVfvOpO70G8zbmSsZutvV;K7VWNf8Yko<-*>wuFt zpEH^D+^&xoku(apk4wgIDk{62GREDJF_Ct9-cIwIED;(^7ZY$~f0c@1;-hki{hA){ z%tgG&_KWRaf>jmGbsW1l;*8n70unf#j*P^^!^~bV@d=o+lTXsQ;F@!bQ3|t50dHJD zRjtS{m2x%ysw@6I)%oRK0vz`cptmZq{8FM%vI7#v=sz4Uk3xG?#XAQBzs`D4w%d3r zM|&_Hd7WWca9Z3WaOTgEM16^_h~=tQD}Atb$jz3tH*#D;UG_r)8(}!atlRLE z=dR@VGfE&=-EC*&Q+lU8BfTaeIK4570{11DKvEaSJSeUNc=(e9)q)d$2Es~~z zlKP|wXRVcn9HJkrlnu1oYhw%4RbYPgpwnY)b1FU-v3Fy5Q$UwxG;!ivi`>veYR5Xk zh!~)imDnGVd1q0hE~k}&H3=`G&&kUoD|axMUQX07oRWWN#n#J7iw25&Ol_x!EIL2z zT2LWonZimCySc+wn+MtOKd2}CId2L~(LbqsyJb=xnaj+nDA?W>F3?FIXqeNtX~X@4`zzBR|8 zBO@-4)zf8HS9Omb4e!}K)IBNB=c?LuqRTT_t-xMh(*=0Pu7J6liA|vxRGABQa||&H zlLG67k{ksu#yq#kFl&Pib{|e_8vtE)vc4OZ1YJU71){30>gGI|qm;|CUcund8vZqG zoj512=0S`*paUFl5KnR>VjWkqJ9geZsGk@NRoQU9{GGI?=Bi%Q22Mx(qF351i{FQg z$vdXW?QT}h)Gde^3jZuux3-;^OZ@qqy3C2xU_OQSHCV$t4ZC!P0$H~bPwqdN_FfhgXVW}2| z#4I*fH3{?@&pX%wPTH*5yu;58#r6_@kXLaW>@;@B*NzMivlCtBgUL`kS=!6RS<(x} zgn6*i>d5}D;@BDs=<)^jp)|RM-PX=E7SfUPC}J3x$G1Qf5^PpLm~17d3j{uN0O_U< z_*2JTD}d?ElBHELcheqO=sA{XwdP8Uz~bK4oHH$2Ez2{z0{C0HFEK)h%NuRC?-D$G z;@(>IQpDf1rqwXM`b->*9~&GwMZeEAAI3HBjgg3txjl!1Z%aeS3nPBw$_b$_i1?Y< zuuA;&&E@$ILU5y*TbQ05ql;h#wFqq3Uvzqv?MwK+Ct}<>IVr+{G3M~AzUfEg~#17dU9iF;yCd5`n`YCE|>Y6GDWv$ z`3)3}-6x${+`lm#3O1Ta{%Nx_*I)C`klj(-z4fe?v~ntFY{{Od#H@Kq0@8m^^yG=j zUE%c5r`G6Cf%4+mqFMIg&I~blnEXBdjts)WH45$cN6j4Hlb#Q7pHYRF0>l&p7DaDH za{grpwi&A$h6l7_x$E}AAi%9RIC{&|Kv{5MJQt7iV+s zBGSLKNP5@S=7>zqdwt7V^oDH~J8m8=Gu3FED4ZzZHPb%IHo4#=&@1w1MVZK$4tcLp zY^*XTg?ZS@owexD=`mO~;UXItT8s}em&7p}4kE`v_wBZ}Ya2f<@>v-)MbK72MzwRm zKcVfTVEa8y*SWlp&Qm^lGwt;vJCvq?%bXHiHgPoMeB_;JE96gEa_})iLsEEkXSH~y z3F-ASiD*0+pgUlx_^DU8NIpj<10K->Hl4L1ryUzT9n@z^<@ z80#V4&Rq^21Ls4O34&6iXb8QY->+}ShaGJrOGK4z?0UrDg52RBb%#|)-H*z*1{5`e zI4S&%(fYwLZ=!Y?{Yl1C`iO;_C7#vMdMO7JDNRF{Z5DT9(~!CKbq~Py1aMr1*z^9Y zrxpIt4_3+ED?S&`p{d$y-l+WX%2>hAg#@n(=21yuF8dW-wTV;a@d(s@%!tk?b5##i z%?^+h^P2l5PN}8ew$`LAJ8jh@Ulh`=we)d%wedtX725n^rWL8=O|JAjRDX(VE||)k zs*lwn(LCQ^#KJ^WdQAw(<6K`!)b|96&&i+C?|{kOz8yYpm8JO3Ag@EJ4l%C)?;*<+ zjqtNO_fpFwDY)e}VXi%{yol$^ZgGmC*H&xtD0kS)W|sQQdq_(6A_G}Y?-%a+Uig&$ zG06Wcrvle1JrpSA?=AyN#*&sE-MHQ)G(AFyaY?SZq)quO)2v)zXBkZ%g=!|!>r;u_ z_%Y_^piQQeqS07_mzsk{p`>rx;*~a)`;)^#@A2DjlOD$_bTtSc44VJKZ^26jZAIhW z+$RQgLJY17{+5&E>jc^(1CMhbURLCj?j12GgqEqataxm;1i*>3sjaf1D7A|YJlIpu z#p-TfjJ$}w_bLBdUQ1N&?Ql7-}tVHA( z=^Zo}YH2RA-8sqh$lI>k%~M;+_u0m)VM1S3Gq=RU9y_hvD8DsV^RC%3S)PIyGs`i6ARyBTS^WZw0FirOSGtGs2Pmwtl|Mg%9MU;Y1+~kQl znqG?uXh_hi-zte|v`KY-6ESJ|JUk6+l+uXY9tssYKoy!Bw+yD%=Zd$)3lS6oDgT^iw70wP~Z#MxHT@XQBi`%QpD$$nzK zmhe5r#$aVr8jq1mmot&;{DG6h!f76?+Ku|Kws&si^}zWnw2(8HEYz|Bk!gerLMjDl z^lsf;k^(yZ!sM$l0`Y!Q6HA2FrX}?2vP!?R;#w!mYxf6PV7P4_@ahfECu@eOpb zkX>ndOkPC|kfwnh7#vVp=q@e3pZ~zxL~s4bIm*w$KP@g=maljh{}QbT?Qf5HFTO*m zdh8DvU%;fQ;6RvOR9t|zBm^0Xv`d&X;;B*n&6d{!1%6~+l5F7Elu0WsiCQ;?aNJ(v z1&N^0Kb)-ojYS?xvJvRW;QjqSS38s;3@q#rB_8k1l@g>%pU3O`ug?z2{nHNXKNtBo z{8*e+Jl^o*>aYKADjMIRY&7CP&KDmdbF9mE7U=H2?TP~s?~wgRfMCQb>HiC|+zuyK z+lzi{oFm>FZxt)7>giRwt$o?gfrQ)GD_vz<6&A^Qa;nAs6Lb70EpDATm?H|4N*hhW zYgMXDZ!V)dt}qMAE=)F#o?TxEqMEg6_C+6 z@~}-dz$5i%I%Kv$yk})a_G4d z=ZrXF&Ab{(=CQS`OoVhF9VGT&oi~Jyb`zqe(n0_7f`ig`yG?7!ujA5uEd+$cq4)mQjxKoy>}@yo zN)OgIXV+Hep2Q{gBn}+Dl|ZgzXYDzbGiy56T7<9LYk(a6T&$&=Rw*;`&lnyH$V>c~ zL5)4knc?V=!E_Uz)vP#j0$tO7Up|(5JA7Gqa^C^7JK-5FI877eNwzrGrewy>RE+oA z&R;tdp1iBuiPw`K2|roC{=m|OsFMF$#^fII-5mYFlpz7tm?f*aOi>+$MVf~1c@L`) zP$Ru*EIZ)T^LJbGP_!ad@ScGCnRdFFWD2_?MjBu9cyAoinQ`Lj_nIe?F3H$ptu)R> zsrPN=T{~sYSMAGX!)0UniPUsn&{WS<_MbJiw*-z@pE=ja{AA{3-fOMOnyOM6ZGfx$ z`pe|L4InlTN6hyQhgfhMqHz7^BYX2b$tpaR3l9%dmSb=KcK`5o>31Qoz4Xl>gxLqe zPkZj`SnyabE?19fyIJ=43NV~@SgA61o9=LbF>R=`7@6ama^+Q9Pdi-zE7C4M5HDEgCaEVBqsMB;)<$lgxfnVr^wV$2(^Nb!yr(9O(VOm9DD-AX z?{Tu??(5{o`UL+<%#eOMXa-|Y`5yB!F^(hk=Ddce=(RwP6&Iaez}~Ek32ZtUrqt#v zih1Dk6f{~D*StzP>PUI2uL|Yr(z*1&DPg+m)+P0+f-wpO0ZoK^zIQwicFp%QTUsg4 zX-1%n0mymp7%&~9OMs6-iBUKwXruzltq8CAhypW%Oi8l5O!!+kd03YoCdp8kbq398 zi;L(L<)@dPHe|_i{l-t;1NytLxSJIO93!#graG0aKtQA{GxVvqsOzhb@b z?-xqvrEC8I`F~pb4zQ-OHh&NWl{!{X1ZNyk6a=J6R~b%3 zl14kilUmsp5iEn=?f5~jOr8Ai&mya@MUAeTBch@bnB6^9DKeJKGL zNFY$02;K&?lse}vT+usV)Owe)gmB7|7y$6;W4!~0Ip0aCPQL+>SzzBh`&df;qo-vrcdq_CZ_ zUg`Xo<+j`HIMy$HyMOv>)y4Ujodf}BBmcirzhjt@1I{~BYwqKwZ{IW8p96O5-p^nP zyWlvmQwa&VM>zrxOMBS^0ab-F!!m`w>=GA7Sw_Q6v=jX*QtX-YX$tT_-PkBC;#O-% zC*EOxDRtwArhxe|5Vo$=%Ep-Oa6qIh)}0W5-s~wKUKBHiKMetMzQHf?a*0372S7`K zvFOsbeQ$H|$Tj-3J|c>cnsSFQp4O5Uph1KQk|8mYRQ_6EuJKA}VM&|nuk+LSgOVNm zcz;_Pn9_aTVXk-UcSlAHY>TG!M6~79<&-r?+ZsmWfN(;f>+u+F4AW-I$dk=0q#qUSUWEMYE>a?)N!r%$cx5ZFs2aas1Bpq((zpl zR(q%;lEC5Dx9myy(Ahbs3wr8auF5~p4A}I4aF!7!tRhH}hrzib>U?87WiVyjiF_9! z@=&~Wv8a?K=Z>|+LQG=35`l`>(5^8gKd^$J5zdyxjmy62Th=a)IZ2O6w*NUK7XpJl z?|0fQQ8=Vp0r;d11t$Tnb5hxPLO-QrKv*=RHfcfe!an~Q08QU<@CC9{L-BWPfi{=J z4UfnoMxvMpqCdif+va;s(XpQr?l6bXqi?NsxR?CY7cctc77lBrWk8Pp;yQ~C64(6`p*V2hAYs|eYeByaC)4WHpyXg9O4G)aeH;A;RM}w$)oIIp zW(wE>C{iCN^bM}N3FUVbFw}AsIG18btWGg+PIFs#CYleNiRS0XbL>a_Yz`qc`^hvx;j3YwKMbOy)XU_|I5B;8OK(44nJxOO8v`e%2ti{d)|E zSN7lM{Qfyuo!$$grS${nx4_@<)zms9yOX@M55v@nq*`I^(F|j@Gg;;cPFSNuSU{XZ`DqGzwNRE| zeJ)WE%IZTm6ty5ZgzV@#ED93lGbfw%CS3tknJT!EJ(-M)Tq8xYx(~*COn?diVDJ3V zv_NLvIjvi29lH%(!=8t*>xdP1J(1he-D3>{+yCM;PQZpWw@PJ5vKHl16Fe?(BHwTk ztd*=mB44s&JvU&L3K8>N?j4n z+sw3m7j&IYyhr*`py0y^+v6*{_jjP3!p$M>bRRfPlm+E6D8nRqJxpeC*F}^SaT$SgpI`m zCJX#!jd4Uhh7D-eh_G;&CC8h#Qy6hZharq+PfD^WI?p3lQ`t8*LhhWyqE}0gvwpi(NjvCq^4|@&pN-Vf%~yB2%JHlWmLhvq z(ryf^ag@Dg&y+*aRr>` z;`#|9_iUvg16TO3>lyDId)wFzF;_9$#U<~}Da>^bOgl)pz(U{!i33;~oS$H^fThBf zb`(6iV0C~6#kmTW7!OF~!TJEne^#{VQsu_1=!1#m#EMzHxO$Q6p3qLNdyOJoFL<_b zy^!1fcRF>Ci))IXn`^-PnM&ZW3GC|gO4)r-7FTv$IZ{O(k9~NjnnP(+a zM9-lDr|+es+A=tgNc;rrOy-4 zNSFDF!>MK#b}rw$979rN33kj8LpZe|%o5T{G)Io~HF0k&v93hNmb8SG+WB1ZGp08m z`pPm!2%hQv9yCH^AO3A5DXPQoWSjylJSZ$QEN_{Xt&QavVs+@9v~OK;46C2cQ0R9v zfR~dZ6OOMjpywjoO|0=Vt4e%Bwc@vtBcE-#F=xi4k#Fitj_l2;(hN2V+{Q%$FxDS8 zcbHdbrZAqz40{0Gz|!MZ-S;2v8}P)Sfhfs`FPvJ+e3*#GvKqzp4q`lSW6|T~Og>aw zhLOps7=`}Ih=-9#XO?Z3gpHOATvx4W2%J+p9jzWkBGnhWC-K7NXdZb9tm6+2!IX9j z@W5p0HmCg}_6k}vQo0wiZ(Mc9PP*rl)ZFmcwr9aw3Xu7%4EN$_$xNuqTs=4E}@cbLpd7p)a%nX^P!3Mz-V2)qwaeWovgNgqL4l#(H zOt-&`Kja8Dm_*LtJl|}4MAy~`v~@JJW?gLYn2UQBr!Za9Z8O6RnNV{J4_@_5j1`iP zP;L3tk`~y%bEAoB(__!a_XnNNII@^a3``{~y*2skt(6j8*&LX!e*>f7NdHyf0Opm+ zb8nO7vuMO{&u_@VipqXtNFt=1v+rrVmkI22y*-JmdoYnfR+IXzjb^X$!?2yuzon#KYdJsG zqp_nP;s$=^w|6=OXz-!&f&lI@qP(r>v;0&ap!f5%*yWSaxe(E%Q!I+FLAaLem#2Wx zYS>N=p^v+udbjt1XuM&GG%MFTsO2o8Hui0E#swo2ecam``@6{gS>?kqG%GhtmgK@h z6{_u~sEH2c?LN#aE4h9*-=1(__2apdOwnGlFDkA zv3hak!#}jml6*xBrY+u|O1n}O5OMvkr>ae==BT9*QU3c4rcGc%3SxHNtOrYwvrW1cq`M=ezNIZ_A6&FHG>>jFiR=;5}&NhCJ z2)h<8WxT&=7MEhb<9L6}As2qE@WMQhei()vVK)xlJYj&sy%Na}ox3`uk%^xMs^dG0~bKre*? z5ajeUq$+Bf>a?aYq4cf%i-nem@5S=2WLWP&gjBhGZ`_ZRKF%!lluqWo&CE6UG!pV^6qch5cvm;^tVAD=}Lz80>MS4&L>ru+PaNjXc7uxd!Ak?W;`I>vX>hTNAU zkfxMBJcF4}?gm>131b^t%Kf@#zDA5w1QOtX#E0{jeb<&aHu8CiLb>R*fn@#X!JnKxmGsvV(BF_ z%`zdpUmVFkfpL;jxO8U*Vk7#j5eVo3Q(oZfIl%tn8l?z~vO=*!vBi4(G4+q95;H7FAxN{0mqMlt$OozLI;Gf7{{7XQi%UTh?#UJ#PT5z ziZ3_#t*$a*;wBabl&lJU)e2>ib{zu+pA5s8-jzoEJFcn{porS)^dkbnlVseX@kniL zod(*N5OvUuI*#L~hSan)+IEaXPs7%Nrh*)MSIH$#ROLtV&T24t-GUF2fJUp#X7)A~ zJ9~|G4=m}$Q4TK$h8)3TAvTn}At9vABPzTqnX1s}4YVoxdnl%e8p~9AZAp+VCbSq* zHCdV3;S67+3&G3s*RkZ~ z)wEJ};Nom+w7zl@^U(18S76-tJwog^HE3B)f z+PL>cW9a;nb-MIZg})SHr?i1!PR zV~It#qmwd+@beFr_eHA2a!;$B2DA>8bN7#2&zZhcc-+)-uHss-2M;a1`32kNfRW&> z)3AA%AP+%vr?uDX?tKF?`|npp$2LKa!-@{M4!9f}6}ar;1{9jVP2j1+z^rfk4!Lp> z&ywppKIJ{Py|*JXvD%XO-HxqbKYKhEb~Fc{PKM}~J|CW`h{cVGeGSYLfI3fBew+B3 zsSQUI#B{e1XP2%Ei%2?AYX?t!v=;Lh?VDFt%su!~>r8#gYEj^>z1&7#wm|r?sKbIV zPOw?D$R+&R5~(av(bY=q&S$djnYKkG5P{~7Gw?rS;3~RrO-8_UiF-8h&d*g*H%x2X zlj!+`U0`M5N1O%2d_)6KF$#)6OZRxj=*MxW*S$5m6u&@5k@9vZ6$#%&jXW1Hn5sAwN~GM%)3q7>lksi* z9uj7IckG2@2X0Vk1`%)ySI`sTKFUaO`i{%`WK0MdA))ve>JY;&7Dj6EpHgdvO6y_1 znL*+i_uRyBtPeV@5y#c|6KdhkxJA8MO-F$yHQ?7fUCt(^t?!K}!hRz4BCH$@Y+3Vf z+O_55V*=`cMi!nyKUza6IZH=QMGJKt;CtOoiS=6jvbcI#keUKvyd|Pe1BvpYl>rd< z%bHm#j_i>#qr$=;zVPV5Q37{8@w6TS+b^uR^~Ta@lndCwK@GAl>hoQYXlm z)Q8U}jMAEeKlT-MRRZAmYYy1z4~AAGYd?5zEX*TMubq7_@h z;lL6|PD2Q@^yAbTC8F&D6=*MH3wcTF2+lfBEO?-v7^1Z0ZrRCH%D@J3i0hPa_*!=N zp>~&^`qK{%PoJ?56H;SQ5ngse6osCr$AZ)&s2lw z*I`pBF^p$x)EG{itaL?GajNKk#7K`R9K7ly1n!FX9KKQ+qk!cJ5YWy(8c$bp7z=mZ z6__#Sx}>eGt??2k*jLj&Lcisj^L|;8_acIyN`;Mii_UF}Tq_Y%-1`JlN3t{Mk?$bo zvg`u$5ZRHBxIZ%i#NZDWYUWHZA++BmoXaTC7Dk1y#i507v#<#ELg2a3_k$%)J%ldm zuc^=w4vt%Wouj3kKiYXeN@?%Q0Ix^x*MB19PrkXInd*C|&Ud$C$Kz&)H@ltQnrKUW zpo)H1Ld2m&3JgNzo3t&#gS`iFXEyO%PvJ7Q-$V#HE-Z$z6+1iVsyY?EKxg(byO>PJem*C4?zt&WC^>ag+0Li7D7Zwb{fn&$@< zR>iMPRvEyeutxj|enDC;@kj>XIsoGYoC5Y9Jw8VL7J9Nf<&7}#z$S=@@&{P9sH3QV z!LRY3*sL?L2mN^jYKQOt$sDL$f)2vz(z5+-a)pB2gRfiCz?o=R5~%qZ6KW)e=a&Pk z%!SuFFgUa5uRc5ikLv2rWa};6e!vJ(n5)ALF(eqW^9zm*@*Dsw0Y7hlY`aAN~N;!>4$J&n#MtC&>mCF@WD5c$KD) zzks75Ygjd$H>bt6scKkQM}4+0?0nAsdrTpF#j-IwpEo$B`4>s!mD=`#>y5Jh(@Ujd zY>mu*oHe}iFZ*C8@&n{yCjiCW37t#4I8~w0r0$8CPpxNJOrABj9=;H9fz<2rQ_moi zaYPTsjX#~c);vZpLh*4nekE&;I}f=b2aUB}n_5PP-c*n~7W*quM)u@7*C&64(R;#l zkSr?FFIQSOSl;MwmHo~xO;zW30XhCry|xcZ(Bvwr-=Vx!2|@9CzgyQ46r$iso6CZCMyFteSS zwGTY|YxC1JyDM<{-MxK6*zT6Jut=58Z?y`Oz!!mURqwA{K-RZD?gxP@rk~#W*xZnT zk87US(|Io_hVw>WtJ3Y7*9H%wKia9(3}E3sVTE&vR!JrqJ8opJK7;>tbGO&<{pW3{ zHkaLwU8Eu*3-vjy=63gt>~g!2xshW6(3FaBR-?$aqPRTV5-^YsN$tOk>#Iwta3UT| z1TJ{727(M#FW^)G5{#G#d^{9nLCFs|1(CQ(tjHKBN9%a3h$AYq;ND+|f!!^4jZO3q zT%51Hfk;0|XK2Y5k;9hLHFsV%Zh$4D9#dmgel$#Ie1|QMRSl99wE>uVaXc8HW=>JP znX&WTOeMVnY3{Ags!boU&)_|>R#LZ6a^R?Gg+xi)d$&XP!awoW(153i$Ec`CRCeN| zgB;o^K-#qW$P>uQ62!K^eGG!}()hUTnQ;td)g0jXYW}&Z(ZB83kvQoGkIf5?tX6G=RVi6Yu!PT7ymzt2bnOH{(vzIkMcFyVi0{`(5gMVJyCqH2G$io;azo0F{cplq z@#G-Y6q1z<<3OmQsnKGs2<`oa1LCGso6hIe_8$Cjen%7Sif<;PE+b{EMgFFNXmsj2 zS7YdOTD(Cds4+nirM|KUN9A}a%i)WuTu|h9hqQK+vxi-#U4A`}ts-0&D3-v?=SHt& z2BHBroYA=c$Mdx*+QYxR$Ae4@|4dTpHfR%0> zk$CN7cdNb^Vmc6g>quw(R3HI__Q3Dz-c4S8*GwrO)Phsv_iINwB67ZC`l0_9F%kSkot>K%rq$E_o zXmY~5oH)RzeONZSdFb5H$US&Q!~vmBm3o((TJsR`QUtC9$D1@weJqFs5GT?mH|%mg zu_yDFXWk>Qiiw)&YU|hC#AepeYe9@jIAo^ON7Xt$tUqFOu(yPL*}WG&dmtNZz(p?0ZjI#*mv zuQOODtsZ$%Kiz}Jfrv8ApKY4$DW#B90?PoNThg~nF9@Z*goFGS=JGfEu2LZ_ww@wtg;Ee{L@_jZ?wjJ1Csjt48L_4|93}r`4Z)l zf4Hz!>@(n{fv9G){C`BcwvPOpz||HWc1AC6Ez>5FR_|WDj>4>CF@6WyCoGpyKx0e- zvjNU<{7s+1HEDoDLlxzET&sSonWC?QYBLo7P-0Zrh!1~A3|n9&$&SO(*G|^1r+@sLlggd zB3Y2oPN8f@MNFWa<~>4k*s-nOp|b!6!#?KMf=^A}{#T((K zhCLAmKOIM0atyi4z1%tJ7!ql@%zL*JVvbvDA5%cGn;q%khtBhmh)_CW*{FZe?D z@1WBK--==sgb57W2f%#Dn+y&+4LuslC*{o2s8ZUbqw&G9hSuy;57X5yGcIue!KQT4 zm0eKYs$XJ-p~Ls@pAx0-gVQ|Y$!M+CRXFfY$C-)NCM2-BYUQTr3+(ikNGb3wwdtI- zENZwMnD7L*5DsYrdq$4pUO4Ud#_qhHu+C&kPu*M_Wre8`=cH{@<^KIj;O8NmIAX|( zV*TK5BL8P^XP%!P3v{3gU3LKHp;|&pxD)pM3KgP}t6FhegH;Sa<7oI0i{v}*MZIBP z)wZxOgSPNU?EXLth1jquduIy|57l~oAmNKCg~@}B5^X`I_Q(&_THR1-RM{x-(O2P# z?%uu*+q&HTY5|;gb^PgmeN9^&o&Tv@)ctox3~AOm(f$z+yO(+cf=PPOXvDCRf7)(d z>D_;nnb^z--_<7fTYYMScH~@(%&WV7r4ewCd5hX*gH$mo;J$U=&wBE8N!4T?9|qMdkVP(7K+*VlrN@yj2W^e=3Kh^JtE&)YZP+B}o&?F-z8 z_!NE*5lz*|EFQTKhF3a`s6G6pu&B$K|H8+_A1>8DhPUZPC~v6|=x3 z=Uh`ozd2{_Ccu`5rvlkKjoF{wHvg={yW4Nvc|qZzAY*2_Pezx~Wj z$D}9c`22A%RI=m^U+kr;mGY}YkD?g z;;w}*AIe&!hi9O~(YufEw6-o7DP8+8PoT{DgPJU{Lfrv{2nd9>B}avdfv|EXa4v5U zxa6kucp>8&PvgT*brMo=%+F+1EPSQj^SMvK$!^;dNq2G_I#T7WTo8tg>1^}RVb>bc zsCOQdZc-Sne`K!vMX^wUYvHhAX7MC#EEFPy(KMue3v}^TnmJdMygu+2p3D< zk9j67ZHHRhxF$AFUvgvI2O*75LeF%cv+Wuf(DnL)3WzP2G@rSHzTu-g9gbkF4!>R2 z7}joCsw`NsdmgfzqhxUh!55J#7XOKd=`+n{^!A=luXO?=Xx=>JjCoE@5lHqupa^vq zi%*y98WTOq@IwgETzbq&f|ze(sgP?6_4RlCSn)HVc{v+XAO|9y@g2y;6R+G+<>;z8fzI=zt3{bPC%pNrrW z+{hg*xBy&mUN0F88dX|s|MM@aJ+b?zlrX4;79m~YfEFLx{tgR@1Kpd zcUaUH%mUL|Jtg=_s7*~oSv6$+Rd8DCN2VD#+3$@$RUGvsE1>Rb!`o=zmsG^V2APg9+RzycGaNUmU%hjcqkZ46)&v-`=N* z$`6yj5F8h5{;YVKqE2hQcLSpF-NQFrW+e0I`Z_n3{{ee?vqq|&5-?kZ(Ms&2&&4O9 zl&ZT%lv2%aUWe)k_z-PRn|R%e)Y6hG(b(gn*E%Hr*yW^;^!Py?tI*8*T#*PECV>q7 zF&z?`m}>IH|4a*o|J@C^=)1dnB8sB?(`E=(uYGv3M`*ssklr>829da7_kx1r*oezR z*#TqrZ|0!akMkydKa8_C06yYTYmm@xD*u-Svzcd{^gyb|HKgINge8SEzksX=4Hs7C zG|NoqIEQ9aQ+Lz640T^0+{Bjc;=A_PKnCZkN1^>jtgup34bIYjr4-!7ba@)L*}%xs zoF_MH2mC31wclYY%J&s)rbkzIz{_$LhZg;N|87HZfhGYl@1Gqvoq?Mm31d1W3%c8; z3GwX=1)}Qw2?S>lL{}7m^z}fjj@ct}RhWj6@I?*Ly*m9hky$y2r3K)|lD#*ldb}Mt z5HMPWDfL8DJ%Z&FEaJBPTI^t$vw!LJQ#O_G6IQE}Pay^bs7b|<@}LTuiB zxaHfO7oa(QFjynQm^eswLyJG8r?u~K8I_5Vthhb7fRs)wIuQRU3Spc~tH1HwO*UCN zzi#4k>06(KbmL2QFE<9{vyE}y52*Q7vI*iG;TZ3+TR-v+#1Bc&Q6m1@$Bszt(z)99 zz2*1nGV_q}5q$=6@x%G6Udu*8AD>rPxW7+hIF>J8vtW%*xe-P$tomGo7?2v_$()IE z_}X?|E1?(f8+4gwf?)3Is`wc!E9x&g9F;uft(k*ulmi1eh}GF9y;wY6KHvuNdiKwszRP0xb?q3=c1OBkq%R$Tv9(Q~&8 zHJNcz?nNE0I-;yMf-yZ%gMm2MtBvVX651JBeWh}=m z+8pNC8Mo)GlJK|tbULMR7Sp^?y@}f|oTjW4UY8w-UIY@;RwQJH&7F*5#|JlUBkbD6v4laN=jdg|Qbcx1Jh%@RJuo>&8bi z#1t*u&@{)h9xh5rerl`t6%zSoq`LmHGMH!Oo@9?;sEPj>sgUsG{>d;e-Ya0AFej)H z?)dTLY2-$BruBol$bMdVnAU+H$sBA0Q&HdJ<3&mT@KeYj+27+*xU6{>jre$TCjJaP zw7<>o=YWG$l3o!lNko@UT+m2Rdiz zJpS4E_S?d#Y?!HkcFusJtI{e7?fnOA+i5&k8p>s|toZ$oGBCS#Gtk&(Nejiu=mg|5IKF=&S< z2X!P@2WvwKGt%2cp)qG12yx~kc4?jVuk5ss0y-AOW{NJ zD@?Kn&P2N~n-Eeq7N_MD3i-yCvKtw$WjMMeY2COU$$;Jy zRL)D4M~Bt7ICq)A|6NgNtxhv{;|aX5qVV|m8HxJH_hBG<+kGpARd7(c7X^=!j2`Hl zzfH-aArTCm8DeXlwFOKD4G{dtHH>I^8x+J=qBuA2MM+L^wgAx;ZVm}9-iXaNKi}r% ztz7Gu|GT;VfjILe4?0h2<=OAk_-pG72)a7&){hfcd;72Qu|mK*c14-8^W&A?WCMI+ lpDtSyY!UzGpC6Cuk}py|cn8gr&T)uey=3%9$wi0z{{qvfEGPf~ literal 0 HcmV?d00001 diff --git a/docs/api_FiniteVolume.rst b/docs/api_FiniteVolume.rst new file mode 100644 index 00000000..40e9b879 --- /dev/null +++ b/docs/api_FiniteVolume.rst @@ -0,0 +1,19 @@ +.. _api_FiniteVolume: + +Finite Volume +************* + +Any numerical implementation requires the discretization of continuous functions into discrete approximations. These approximations are typically organized in a mesh, which defines boundaries, locations, and connectivity. Of specific interest to geophysical simulations, we require that averaging, interpolation and differential operators be defined for any mesh. In SimPEG, we have implemented a staggered mimetic finite volume approach (`Hyman and Shashkov, 1999 `_). This approach requires the definitions of variables at either cell-centers, nodes, faces, or edges as seen in the figure below. + +.. image:: images/finitevolrealestate.png + :width: 400 px + :alt: FiniteVolume + :align: center + + +.. toctree:: + :maxdepth: 2 + + api_Mesh + api_DiffOps + api_InnerProducts diff --git a/docs/api_ForwardProblem.rst b/docs/api_ForwardProblem.rst index b8f2fd90..0bf9596f 100644 --- a/docs/api_ForwardProblem.rst +++ b/docs/api_ForwardProblem.rst @@ -61,11 +61,6 @@ If the forward problem is invertible, then we can rearrange for \\(\\frac{\\part This can often be computed given a vector (i.e. \\(J(v)\\)) rather than stored, as \\(J\\) is a large dense matrix. -.. math:: - - u(m) - - The API ======= @@ -78,7 +73,7 @@ Problem Survey ------ - .. automodule:: SimPEG.Survey :members: + :undoc-members: diff --git a/docs/api_Inverse.rst b/docs/api_Inversion.rst similarity index 56% rename from docs/api_Inverse.rst rename to docs/api_Inversion.rst index bd4d8704..5cac5f0c 100644 --- a/docs/api_Inverse.rst +++ b/docs/api_Inversion.rst @@ -1,21 +1,19 @@ -.. _api_Inverse: -Regularization -************** +InvProblem +********** -.. automodule:: SimPEG.Regularization +.. automodule:: SimPEG.InvProblem :show-inheritance: :members: :undoc-members: -Optimize -******** +Inversion +********* -.. automodule:: SimPEG.Optimization +.. automodule:: SimPEG.Inversion :show-inheritance: - :private-members: :members: :undoc-members: @@ -27,12 +25,3 @@ Directives :members: :undoc-members: -Inversion -********* - -.. automodule:: SimPEG.Inversion - :show-inheritance: - :members: - :undoc-members: - - diff --git a/docs/api_InversionComponents.rst b/docs/api_InversionComponents.rst new file mode 100644 index 00000000..eeaf1bbf --- /dev/null +++ b/docs/api_InversionComponents.rst @@ -0,0 +1,11 @@ +Inversion Components +******************** + +.. toctree:: + :maxdepth: 3 + + api_DataMisfit + api_Regularization + api_Optimization + api_Inversion + diff --git a/docs/api_Mesh.rst b/docs/api_Mesh.rst index a7f7abae..ed216b13 100644 --- a/docs/api_Mesh.rst +++ b/docs/api_Mesh.rst @@ -24,8 +24,7 @@ the implementations. .. plot:: from SimPEG import Examples - Examples.Mesh_ThreeMeshes.run() - + Examples.Mesh_Basic_Types.run() Variable Locations and Terminology diff --git a/docs/api_MeshCode.rst b/docs/api_MeshCode.rst index a3813c13..2d7cab9f 100644 --- a/docs/api_MeshCode.rst +++ b/docs/api_MeshCode.rst @@ -9,6 +9,15 @@ Tensor Mesh :undoc-members: +Cylindrical Mesh +================ + +.. automodule:: SimPEG.Mesh.CylMesh + :show-inheritance: + :members: + :undoc-members: + + Tree Mesh ========= @@ -21,16 +30,7 @@ Tree Mesh Curvilinear Mesh ================ -.. automodule:: SimPEG.Mesh.Curvilinear - :show-inheritance: - :members: - :undoc-members: - - -Cylindrical Mesh -================ - -.. automodule:: SimPEG.Mesh.CylMesh +.. automodule:: SimPEG.Mesh.CurvilinearMesh :show-inheritance: :members: :undoc-members: diff --git a/docs/api_Optimization.rst b/docs/api_Optimization.rst new file mode 100644 index 00000000..85ec523f --- /dev/null +++ b/docs/api_Optimization.rst @@ -0,0 +1,9 @@ + +Optimize +******** + +.. automodule:: SimPEG.Optimization + :show-inheritance: + :private-members: + :members: + :undoc-members: diff --git a/docs/api_Regularization.rst b/docs/api_Regularization.rst new file mode 100644 index 00000000..4ea1a554 --- /dev/null +++ b/docs/api_Regularization.rst @@ -0,0 +1,100 @@ + +Regularization +************** + +If there is one model that has a misfit that equals the desired tolerance, then there are infinitely many other models which can fit to the same degree. The challenge is to find that model which has the desired characteristics and is compatible with a priori information. A single model can be selected from an infinite ensemble by measuring the length, or norm, of each model. Then a smallest, or sometimes largest, member can be isolated. Our goal is to design a norm that embodies our prior knowledge and, when minimized, yields a realistic candidate for the solution of our problem. The norm can penalize variation from a reference model, spatial derivatives of the model, or some combination of these. + +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: + +.. math:: + + R(m) = \int_\Omega \frac{\alpha_x}{2}\left(\frac{\partial m}{\partial x}\right)^2 + \frac{\alpha_y}{2}\left(\frac{\partial m}{\partial y}\right)^2 \partial v + +Our discrete gradient operator works on cell centers and gives the derivative on the cell faces, which is not where we want to be evaluating this integral. We need to average the values back to the cell-centers before we integrate. To avoid null spaces, we square first and then average. In 2D with ij notation it looks like this: + +.. math:: + + R(m) \approx \sum_{ij} \left[\frac{\alpha_x}{2}\left[\left(\frac{m_{i+1,j} - m_{i,j}}{h}\right)^2 + \left(\frac{m_{i,j} - m_{i-1,j}}{h}\right)^2\right] \\ + + \frac{\alpha_y}{2}\left[\left(\frac{m_{i,j+1} - m_{i,j}}{h}\right)^2 + \left(\frac{m_{i,j} - m_{i,j-1}}{h}\right)^2\right] + \right]h^2 + +If we let D_1 be the derivative matrix in the x direction + +.. math:: + + \mathbf{D}_1 = \mathbf{I}_2\otimes\mathbf{d}_1 + +.. math:: + + \mathbf{D}_2 = \mathbf{d}_2\otimes\mathbf{I}_1 + +Where d_1 is the one dimensional derivative: + +.. math:: + + \mathbf{d}_1 = \frac{1}{h} \left[ \begin{array}{cccc} + -1 & 1 & & \\ + & \ddots & \ddots&\\ + & & -1 & 1\end{array} \right] + +.. math:: + + R(m) \approx \mathbf{v}^\top \left[\frac{\alpha_x}{2}\mathbf{A}_1 (\mathbf{D}_1 m) \odot (\mathbf{D}_1 m) + \frac{\alpha_y}{2}\mathbf{A}_2 (\mathbf{D}_2 m) \odot (\mathbf{D}_2 m) \right] + +Recall that this is really a just point wise multiplication, or a diagonal matrix times a vector. When we multiply by something in a diagonal we can interchange and it gives the same results (i.e. it is point wise) + +.. math:: + + \mathbf{a\odot b} = \text{diag}(\mathbf{a})\mathbf{b} = \text{diag}(\mathbf{b})\mathbf{a} = \mathbf{b\odot a} + +and the transpose also is true (but the sizes have to make sense...): + +.. math:: + + \mathbf{a}^\top\text{diag}(\mathbf{b}) = \mathbf{b}^\top\text{diag}(\mathbf{a}) + +So R(m) can simplify to: + +.. math:: + + R(m) \approx \mathbf{m}^\top \left[\frac{\alpha_x}{2}\mathbf{D}_1^\top \text{diag}(\mathbf{A}_1^\top\mathbf{v}) \mathbf{D}_1 + \frac{\alpha_y}{2}\mathbf{D}_2^\top \text{diag}(\mathbf{A}_2^\top \mathbf{v}) \mathbf{D}_2 \right] \mathbf{m} + +We will define W_x as: + +.. math:: + + \mathbf{W}_x = \sqrt{\alpha_x}\text{diag}\left(\sqrt{\mathbf{A}_1^\top\mathbf{v}}\right) \mathbf{D}_1 + + +And then W as a tall matrix of all of the different regularization terms: + +.. math:: + + \mathbf{W} = \left[ \begin{array}{c} + \mathbf{W}_s\\ + \mathbf{W}_x\\ + \mathbf{W}_y\end{array} \right] + +Then we can write + +.. math:: + + R(m) \approx \frac{1}{2}\mathbf{m^\top W^\top W m} + +The API +------- + +.. autoclass:: SimPEG.Regularization.BaseRegularization + :members: + :undoc-members: + + +.. autoclass:: SimPEG.Regularization.Tikhonov + :show-inheritance: + :members: + + + diff --git a/docs/api_Utilities.rst b/docs/api_Utilities.rst new file mode 100644 index 00000000..c3a08b30 --- /dev/null +++ b/docs/api_Utilities.rst @@ -0,0 +1,10 @@ +Utilities +********* + +.. toctree:: + :maxdepth: 2 + + api_Solver + api_Maps + api_Utils + api_Tests diff --git a/docs/api_Utils.rst b/docs/api_Utils.rst index 042aef67..1bf86516 100644 --- a/docs/api_Utils.rst +++ b/docs/api_Utils.rst @@ -1,8 +1,5 @@ -.. _api_Utils: - - -Utilities -********* +Utils +***** .. automodule:: SimPEG.Utils :members: @@ -52,7 +49,7 @@ Interpolation Utilities :undoc-members: Counter Utilities -======================= +================= :: class MyClass(object): diff --git a/docs/api_bigPicture.rst b/docs/api_bigPicture.rst index ef7c1174..90266650 100644 --- a/docs/api_bigPicture.rst +++ b/docs/api_bigPicture.rst @@ -1,17 +1,69 @@ -.. _api_license: - Why SimPEG? -*********** +=========== +Our essential functions as researchers are the pursuit and dissemination of knowledge through research and education. As scientists we +seek to find models that reproduce the observations that we make in the world. In geophysics, we use inverse theory to mathematically +create models of the earth from measured data. It is a difficult problem with many moving pieces: physics, discretization, simulation, +regularization, optimization, computer science, linear algebra, geology. Exploring each of these disciplines can take a career, if you +are so inclined, but as geophysicists we care about the combination: how to pull these disciplines together to answer our questions. +This is the first problem we hope to help solve: to create a toolbox for the geophysicist that allows you to work at a high level and +keep your geophysical question in focus. However, a toolbox is not enough. The research questions that we are interested in surround +the integration of information to make better decisions. + +We believe that the feedback loops in the geosciences could use some serious work. For example, collect multiple data-sets from the +same field area (geology, seismic, electromagnetics, hydrogeology), process the data separately, and then reconvene with your +multidisciplinary team. You may be rather surprised (or not) that the everyone has a (completely!?) different model. Dissonant at best, +but often conflicting in the details. Therein lies the second problem: how do we integrate these geoscience fields? Not by force or +even by default, but at least to have the option of quantitative communication and built in feedback loops. What we require is an +implementation that is inherently and unequivocally modular, with all pieces available to manipulation. Black-box software, where the +implementations are hidden, obfuscated, or difficult to manipulate, do not promote experimentation and investigation. We are working on +a framework that exposes the details of the implementation to the geophysicist in a manner that promotes productivity and question +based interrogation. This framework can be easily extended to encompass many geophysical problems and is built with the inverse problem +as the fundamental goal. + +The future we see is a mix of tools that span our disciplines, and a framework that allows us to integrate many different types of +geophysical data so that we can communicate effectively and experiment efficiently. A toolbox combined with a framework that allows you +to solve your own problems, and creates opportunities for us to work together to better image and understand the subsurface. What we +are building is called SimPEG, simulation and parameter estimation in geophysics. We are building it in the open. We are testing it. +Breaking it. Building it. Fixing it. Using it. If you believe, like we do, that geophysics can be more innovative and informative in +the open and that these tools are necessary and invaluable in education as well as research, then you should get in touch. There is a +lot of work to do! The Big Picture -=============== +--------------- + +Defining a well-posed inverse problem and solving it is a complex task that requires many components that must interact. It is helpful +to view this task as a workflow in which various elements are explicitly identified and integrated. The figure below outlines the inversion components that consists of inputs, implementation, and evaluation. The inputs are composed of the geophysical data, the equations which are a mathematical description of the governing physics, and prior knowledge or assumptions about the setting. The implementation consists of two broad categories: the forward simulation and the inversion. The **forward simulation** is the means by which we solve the governing equations given a model and the **inversion components** evaluate and update this model. We are considering a gradient based approach, which updates the model through an optimization routine. The output of this implementation is a model, which, prior to interpretation, must be evaluated. This requires considering, and often re-assessing, the choices and assumptions made in both the input and implementation stages. + +.. image:: InversionWorkflow-PreSimPEG.png + :width: 400 px + :alt: Components + :align: center + + +A Comprehensive Framework +------------------------- + +There are an overwhelming amount of choices to be made as one works through the forward modeling and inversion process (see figure above). As a result, software implementations of this workflow often become complex and highly interdependent, making it difficult to interact with and to ask other scientists to pick up and change. Our approach to handling this complexity is to propose a framework, (see below), that compartmentalizes the implementation of inversions into various units. We present it in this specific modular style, as each unit contains a targeted subset of choices crucial to the inversion process. .. image:: InversionWorkflow.png :width: 400 px :alt: Framework :align: center +The process of obtaining an acceptable model from an inversion generally requires the geophysicist to perform several iterations of the inversion workflow, rethinking and redesigning each piece of the framework to ensure it is appropriate in the current context. Inversions are experimental and empirical by nature and our software package is designed to facilitate this iterative process. To accomplish this, we have divided the inversion methodology into eight major components (See figure above). The (:class:`SimPEG.Mesh.BaseMesh`) class handles the discretization of the earth and also provides numerical operators. The forward simulation is split into two classes, the (:class:`SimPEG.Survey.BaseSurvey`) and the (:class:`SimPEG.Problem.BaseProblem`). The (:class:`SimPEG.Survey.BaseSurvey`) class handles the geometry of a geophysical problem as well as sources. The (:class:`SimPEG.Problem.BaseProblem`) class handles the simulation of the physics for the geophysical problem of interest. Although created independently, these two classes must be paired to form all of the components necessary for a geophysical forward simulation and calculation of the sensitivity. The (:class:`SimPEG.Problem.BaseProblem`) creates geophysical fields given a source from the (:class:`SimPEG.Survey.BaseSurvey`). The (:class:`SimPEG.Survey.BaseSurvey`) interpolates these fields to the receiver locations and converts them to the appropriate data type, for example, by selecting only the measured components of the field. Each of these operations may have associated derivatives with respect to the model and the computed field; these are included in the calculation of the sensitivity. For the inversion, a (:class:`SimPEG.DataMisfit.BaseDataMisfit`) is chosen to capture the goodness of fit of the predicted data and a (:class:`SimPEG.Regularization.BaseRegularization`) is chosen to handle the non-uniqueness. These inversion elements and an Optimization routine are combined into an inverse problem class (:class:`SimPEG.InvProblem.BaseInvProblem`). (:class:`SimPEG.InvProblem.BaseInvProblem`) is the mathematical statement that will be numerically solved by running an Inversion. The (:class:`SimPEG.Inversion.BaseInversion`) class handles organization and dispatch of directives between all of the various pieces of the framework. -Explaining The Big Picture -========================== +The arrows in the figure above indicate what each class takes as a primary argument. For example, both the (:class:`SimPEG.Problem.BaseProblem`) and (:class:`SimPEG.Regularization.BaseRegularization`) classes take a (:class:`SimPEG.Mesh.BaseMesh`) class as an argument. The diagram does not show class inheritance, as each of the base classes outlined have many subtypes that can be interchanged. The (:class:`SimPEG.Mesh.BaseMesh`) class, for example, could be a regular Cartesian mesh (:class:`SimPEG.Mesh.TensorMesh`) or a cylindrical coordinate mesh (:class:`SimPEG.Mesh.CylMesh`), which have many properties in common. These common features, such as both meshes being created from tensor products, can be exploited through inheritance of base classes, and differences can be expressed through subtype polymorphism. Please look at the documentation here for more in-depth information. + + +.. include:: ../CITATION.rst + +Authors +------- + +.. include:: ../AUTHORS.rst + +License +------- + +.. include:: ../LICENSE diff --git a/docs/api_installing.rst b/docs/api_installing.rst index e0e7ab59..23938dee 100644 --- a/docs/api_installing.rst +++ b/docs/api_installing.rst @@ -1,7 +1,7 @@ .. _api_installing: -Installation -************ +Getting Started with SimPEG +*************************** Dependencies ============ diff --git a/docs/api_license.rst b/docs/api_license.rst deleted file mode 100644 index b8f2d439..00000000 --- a/docs/api_license.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. _api_license: - -License -******* - -.. include:: ../LICENSE - -Authors -******* - -.. include:: ../AUTHORS.rst - - -Projects Using SimPEG -********************* - -.. include:: ../PROJECTS.rst diff --git a/docs/em/api_Utils.rst b/docs/em/api_Utils.rst index b7e9ea45..8ae98855 100644 --- a/docs/em/api_Utils.rst +++ b/docs/em/api_Utils.rst @@ -7,7 +7,7 @@ sources, and analytic functions. Analytic Functions - Time ========================= -.. automodule:: SimPEG.EM.Utils.Ana.TEM +.. automodule:: SimPEG.EM.Analytics.TDEM :show-inheritance: :members: :undoc-members: @@ -17,7 +17,7 @@ Analytic Functions - Time Analytic Functions - Frequency ============================== -.. automodule:: SimPEG.EM.Utils.Ana.FEM +.. automodule:: SimPEG.EM.Analytics.FDEM :show-inheritance: :members: :undoc-members: @@ -27,8 +27,7 @@ Analytic Functions - Frequency Sources ======= -.. automodule:: SimPEG.EM.Utils.Sources.magneticDipole +.. autoclass:: SimPEG.EM.FDEM.SrcFDEM.MagDipole :show-inheritance: :members: :undoc-members: - :inherited-members: diff --git a/docs/em/index.rst b/docs/em/index.rst index 8cbb8619..fdf4dc19 100644 --- a/docs/em/index.rst +++ b/docs/em/index.rst @@ -9,7 +9,7 @@ Time Domian Electromagnetics ---------------------------- .. toctree:: - :maxdepth: 2 + :maxdepth: 2 api_TDEM_derivation @@ -18,7 +18,7 @@ Code for Time Domian Electromagnetics ------------------------------------- .. toctree:: - :maxdepth: 2 + :maxdepth: 2 api_TDEM @@ -28,7 +28,6 @@ Frequency Domian Electromagnetics .. toctree:: :maxdepth: 2 - api_ForwardProblem api_FDEM diff --git a/docs/index.rst b/docs/index.rst index d3ec4e8c..be173aae 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,25 +1,38 @@ +.. image:: https://raw.github.com/simpeg/simpeg/master/docs/simpeg-logo.png + :alt: SimPEG Logo + SimPEG Documentation ******************** -.. image:: simpeg-logo.png - :width: 300 px - :alt: SimPEG - :align: center +.. image:: https://img.shields.io/pypi/v/SimPEG.svg + :target: https://crate.io/packages/SimPEG/ + :alt: Latest PyPI version -SimPEG: Simulation and Parameter Estimation in Geophysics +.. image:: https://img.shields.io/pypi/dm/SimPEG.svg + :target: https://crate.io/packages/SimPEG/ + :alt: Number of PyPI downloads -SimPEG is a framework and a collection of tools that aid in the development of -large-scale geophysical inversion codes. -The vision is to create a modular and extensible package for -finite volume simulation and parameter estimation with -applications to geophysical imaging and subsurface flow. To enable -these goals, this package has the following features: +.. image:: https://img.shields.io/badge/license-MIT-blue.svg + :target: https://github.com/simpeg/simpeg/blob/master/LICENSE + :alt: BSD 3 clause license. -- is modular with respect to ... everything! -- is built with the (large-scale) inverse problem in mind -- provides a framework for geophysical and hydrogeologic problems -- supports 1D, 2D and 3D problems -- provides a set of commonly used visualization utilities +.. image:: https://img.shields.io/travis/simpeg/simpeg.svg + :target: https://travis-ci.org/simpeg/simpeg + :alt: Travis CI build status + +.. image:: https://img.shields.io/coveralls/simpeg/simpeg.svg + :target: https://coveralls.io/r/simpeg/simpeg?branch=master + :alt: Coverage status + +Simulation and Parameter Estimation in Geophysics - A python package for simulation and gradient based parameter estimation in the context of geophysical applications. + +Our 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: + +* modular with respect to the spacial discretization, optimization routine, and geophysical problem +* built with the inverse problem in mind +* provides a framework for geophysical and hydrogeologic problems +* supports 1D, 2D and 3D problems +* designed for large-scale inversions About SimPEG @@ -29,56 +42,8 @@ About SimPEG :maxdepth: 2 api_bigPicture - api_license - - -Getting Started with SimPEG -*************************** - -.. toctree:: - :maxdepth: 2 - api_installing -Discretization -************** - -.. toctree:: - :maxdepth: 3 - - api_Mesh - api_DiffOps - api_InnerProducts - -Forward Problems -**************** - -.. toctree:: - :maxdepth: 2 - - api_ForwardProblem - -Inversion -********* - -.. toctree:: - :maxdepth: 3 - - api_DataMisfit - api_Inverse - -Utility Codes -************* - -.. toctree:: - :maxdepth: 2 - - api_Solver - api_Maps - api_Utils - api_Tests - - Packages ******** @@ -88,20 +53,46 @@ Packages em/index flow/index -Developer's Documentation -************************* +Examples +******** -* Travis-CI Testing - .. image:: https://travis-ci.org/simpeg/simpeg.svg?branch=master - :target: https://travis-ci.org/simpeg/simpeg - :alt: Master Branch - :align: center +.. toctree:: + :maxdepth: 2 -* Coveralls Testing - .. image:: https://coveralls.io/repos/simpeg/simpeg/badge.png?branch=master - :target: https://coveralls.io/r/simpeg/simpeg?branch=master - :alt: Coveralls - :align: center + api_Examples + + +Finite Volume +************* + +.. toctree:: + :maxdepth: 3 + + api_FiniteVolume + +Forward Problems +**************** + +.. toctree:: + :maxdepth: 3 + + api_ForwardProblem + +Inversion Components +******************** + +.. toctree:: + :maxdepth: 3 + + api_InversionComponents + +Utility Codes +************* + +.. toctree:: + :maxdepth: 3 + + api_Utilities Project Index & Search @@ -110,11 +101,3 @@ Project Index & Search * :ref:`genindex` * :ref:`modindex` * :ref:`search` - -Examples -******** - -.. toctree:: - :maxdepth: 2 - - api_Examples From 1700f4f9c068464b770f7f9909d6eb20a29331b7 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Thu, 14 Jan 2016 14:00:55 -0800 Subject: [PATCH 19/19] add Ainv.clean() to fdem fields, jvec, jtvec --- SimPEG/EM/FDEM/FDEM.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/SimPEG/EM/FDEM/FDEM.py b/SimPEG/EM/FDEM/FDEM.py index f2167fd8..3295fd0c 100644 --- a/SimPEG/EM/FDEM/FDEM.py +++ b/SimPEG/EM/FDEM/FDEM.py @@ -50,7 +50,7 @@ class BaseFDEMProblem(BaseEMProblem): Srcs = self.survey.getSrcByFreq(freq) ftype = self._fieldType + 'Solution' F[Srcs, ftype] = sol - + Ainv.clean() return F def Jvec(self, m, v, f=None): @@ -89,6 +89,7 @@ class BaseFDEMProblem(BaseEMProblem): Jv[src, rx] = P(Df_Dm) + Ainv.clean() return Utils.mkvc(Jv) def Jtvec(self, m, v, f=None): @@ -139,7 +140,8 @@ class BaseFDEMProblem(BaseEMProblem): Jtv += - np.array(du_dmT,dtype=complex).real else: raise Exception('Must be real or imag') - + + ATinv.clean() return Jtv def getSourceTerm(self, freq):