diff --git a/.bumpversion.cfg b/.bumpversion.cfg index f739d080..ea37cced 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 0.1.3 +current_version = 0.1.9 files = setup.py SimPEG/__init__.py docs/conf.py diff --git a/.travis.yml b/.travis.yml index c2c672bf..258c4b7b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,17 +4,24 @@ python: sudo: false +addons: + apt: + packages: + - gcc + - gfortran + - libopenmpi-dev + - libmumps-seq-dev + - libblas-dev + - liblapack-dev + env: - - TEST_DIR=tests/em/examples - - TEST_DIR=tests/em/fdem/forward + - TEST_DIR="tests/mesh tests/base tests/utils" - 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 + - TEST_DIR=tests/em/fdem/inverse/adjoint + - TEST_DIR=tests/em/fdem/forward # Setup anaconda before_install: @@ -26,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 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/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 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 ce7e623d..1f52459c 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 @@ -59,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/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/FDEM/FDEM.py b/SimPEG/EM/FDEM/FDEM.py index 3d6c88a7..96fae3c5 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): diff --git a/SimPEG/EM/Examples/CylInversion.py b/SimPEG/Examples/EM_FDEM_1D_Inversion.py similarity index 92% rename from SimPEG/EM/Examples/CylInversion.py rename to SimPEG/Examples/EM_FDEM_1D_Inversion.py index cfcfcfc1..aba70f4b 100644 --- a/SimPEG/EM/Examples/CylInversion.py +++ b/SimPEG/Examples/EM_FDEM_1D_Inversion.py @@ -1,9 +1,16 @@ from SimPEG import * import SimPEG.EM as EM 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)] @@ -24,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) @@ -53,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.-') @@ -81,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/FLOW/Examples/Celia1990.py b/SimPEG/Examples/FLOW_Richards_1D_Celia1990.py similarity index 53% rename from SimPEG/FLOW/Examples/Celia1990.py rename to SimPEG/Examples/FLOW_Richards_1D_Celia1990.py index 24ae82a6..4c90ea7b 100644 --- a/SimPEG/FLOW/Examples/Celia1990.py +++ b/SimPEG/Examples/FLOW_Richards_1D_Celia1990.py @@ -1,8 +1,40 @@ from SimPEG import * 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 @@ -28,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-') @@ -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/DCfwd.py b/SimPEG/Examples/Forward_BasicDirectCurrent.py similarity index 95% rename from SimPEG/Examples/DCfwd.py rename to SimPEG/Examples/Forward_BasicDirectCurrent.py index 33e7aad5..efbb287c 100644 --- a/SimPEG/Examples/DCfwd.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 @@ -12,7 +9,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 +35,11 @@ def run(plotIt=True): phirM = AinvrM*rhsrM 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)"] @@ -69,6 +70,7 @@ def run(plotIt=True): else: axes[i].set_ylabel(" ") axes[i].set_xlabel("x") + plt.show() if __name__ == '__main__': diff --git a/SimPEG/Examples/Linear.py b/SimPEG/Examples/Inversion_Linear.py similarity index 50% rename from SimPEG/Examples/Linear.py rename to SimPEG/Examples/Inversion_Linear.py index b065682b..a8a0eddc 100644 --- a/SimPEG/Examples/Linear.py +++ b/SimPEG/Examples/Inversion_Linear.py @@ -1,29 +1,39 @@ from SimPEG import * -class LinearSurvey(Survey.BaseSurvey): - def projectFields(self, u): - return u -class LinearProblem(Problem.BaseProblem): - """docstring for LinearProblem""" +def run(N=100, plotIt=True): + """ + Inversion: Linear Problem + ========================= - surveyPair = LinearSurvey + Here we go over the basics of creating a linear problem and inversion. - 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) + class LinearSurvey(Survey.BaseSurvey): + def projectFields(self, u): + return u - def Jvec(self, m, v, u=None): - return self.G.dot(v) + class LinearProblem(Problem.BaseProblem): - def Jtvec(self, m, v, u=None): - return self.G.T.dot(v) + 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, plotIt=True): + np.random.seed(1) + mesh = Mesh.TensorMesh([N]) nk = 20 @@ -52,7 +62,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 +73,18 @@ 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) + 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_Basic_Types.py b/SimPEG/Examples/Mesh_Basic_Types.py new file mode 100644 index 00000000..430fe698 --- /dev/null +++ b/SimPEG/Examples/Mesh_Basic_Types.py @@ -0,0 +1,30 @@ +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) + 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__': + run() 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_Creation.py b/SimPEG/Examples/Mesh_QuadTree_Creation.py new file mode 100644 index 00000000..ede69a63 --- /dev/null +++ b/SimPEG/Examples/Mesh_QuadTree_Creation.py @@ -0,0 +1,28 @@ +from SimPEG import * + +def run(plotIt=True): + """ + 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): + 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__': + 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/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 3fec0b99..8431e4ba 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -1 +1,103 @@ -import Linear, DCfwd +# 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 + +__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__': + """ + + 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]) + 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') + 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 exfiles]) + out += '\n\n__examples__ = ["' + '", "'.join(exfiles)+ '"]\n' + 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') + + 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'])) + + print 'Creating: %s.rst'%name + f = open(rst, 'w') + f.write(out) + f.close() + + 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 1e6c91c0..1d5c8c8c 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -90,13 +90,14 @@ # 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 -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 +109,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." @@ -1960,11 +1963,18 @@ 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): + + 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 {} @@ -1975,24 +1985,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 +2018,13 @@ 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: if cells: ax.plot(self.gridCC[:,0], self.gridCC[:,1], 'r.', zs=self.gridCC[:,2]) @@ -2056,7 +2072,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,15 +2087,28 @@ 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): + 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(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())) @@ -2089,8 +2117,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', @@ -2102,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' @@ -2191,7 +2228,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) @@ -2248,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/Regularization.py b/SimPEG/Regularization.py index e3506290..6c5b5f97 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 @@ -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/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 369134e7..cc51fd1f 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.9' __author__ = 'Rowan Cockett' __license__ = 'MIT' __copyright__ = 'Copyright 2014 Rowan Cockett' diff --git a/docs/InversionWorkflow-PreSimPEG.png b/docs/InversionWorkflow-PreSimPEG.png new file mode 100644 index 00000000..2396da69 Binary files /dev/null and b/docs/InversionWorkflow-PreSimPEG.png differ 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_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 7bf398b1..ed216b13 100644 --- a/docs/api_Mesh.rst +++ b/docs/api_Mesh.rst @@ -23,23 +23,8 @@ 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')) - - 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() + from SimPEG import Examples + 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_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: 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/conf.py b/docs/conf.py index 3bb33621..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.3' +version = '0.1.9' # The full version, including alpha/beta/rc tags. -release = '0.1.3' +release = '0.1.9' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. 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/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 new file mode 100644 index 00000000..20b39eb8 --- /dev/null +++ b/docs/examples/Forward_BasicDirectCurrent.rst @@ -0,0 +1,21 @@ +.. _examples_Forward_BasicDirectCurrent: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + +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..d635d8e1 --- /dev/null +++ b/docs/examples/Inversion_Linear.rst @@ -0,0 +1,26 @@ +.. _examples_Inversion_Linear: + +.. --------------------------------- .. +.. .. +.. 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. + + + +.. plot:: + + from SimPEG import Examples + Examples.Inversion_Linear.run() + +.. literalinclude:: ../../SimPEG/Examples/Inversion_Linear.py + :language: python + :linenos: 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_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_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_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: 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/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 diff --git a/setup.py b/setup.py index 531dc539..bcb5b8e3 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 @@ -76,7 +77,7 @@ with open("README.rst") as f: setup( name = "SimPEG", - version = "0.1.3", + version = "0.1.9", packages = find_packages(), install_requires = ['numpy>=1.7', 'scipy>=0.13', @@ -95,5 +96,6 @@ setup( use_2to3 = False, include_dirs=[np.get_include()], ext_modules = extensions, + scripts=scripts, **cythonKwargs ) 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/em/fdem/inverse/derivs/test_FDEM_derivs.py b/tests/em/fdem/inverse/derivs/test_FDEM_derivs.py index 9831d279..f6d0da90 100644 --- a/tests/em/fdem/inverse/derivs/test_FDEM_derivs.py +++ b/tests/em/fdem/inverse/derivs/test_FDEM_derivs.py @@ -39,7 +39,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): diff --git a/tests/examples/test_examples.py b/tests/examples/test_examples.py index 1fcf05f5..2e4803b1 100644 --- a/tests/examples/test_examples.py +++ b/tests/examples/test_examples.py @@ -1,17 +1,20 @@ 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): + def test_func(self): + print '\nTesting %s.run(plotIt=False)\n'%test + getattr(Examples, test).run(plotIt=False) self.assertTrue(True) + return test_func +attrs = dict() +for test in Examples.__examples__: + attrs['test_'+test] = get(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() 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()