organizing the docs - put the content in a content folder. put the SimPEG core api docs in core_api

This commit is contained in:
Lindsey Heagy
2016-05-30 17:06:29 -07:00
parent 414418a996
commit 5e8d3fbc78
57 changed files with 122 additions and 95 deletions
+52
View File
@@ -0,0 +1,52 @@
.. _api_DataMisfit:
Data Misfit
***********
The data misfit using an l_2 norm is:
.. math::
\mu_\text{data} = {1\over 2}\left| \mathbf{W}_d (\mathbf{d}_\text{pred} - \mathbf{d}_\text{obs}) \right|_2^2
If the field, u, is provided, the calculation of the data is fast:
.. math::
\mathbf{d}_\text{pred} = \mathbf{Pu(m)}
\mathbf{R} = \mathbf{W}_d (\mathbf{d}_\text{pred} - \mathbf{d}_\text{obs})
Where P is a projection matrix that brings the field on the full domain to the data measurement locations;
u is the field of interest; d_obs is the observed data; and \\\(\\mathbf{W}_d\\\) is the weighting matrix.
The derivative of this, with respect to the model, is:
.. math::
\frac{\partial \mu_\text{data}}{\partial \mathbf{m}} = \mathbf{J}^\top \mathbf{W}_d \mathbf{R}
The second derivative is:
.. math::
\frac{\partial^2 \mu_\text{data}}{\partial^2 \mathbf{m}} = \mathbf{J}^\top \mathbf{W}_d \mathbf{W}_d \mathbf{J}
The API
=======
.. autoclass:: SimPEG.DataMisfit.BaseDataMisfit
:members:
:undoc-members:
Common Data Misfits
===================
l2 norm
-------
.. autoclass:: SimPEG.DataMisfit.l2_DataMisfit
:members:
:undoc-members:
+8
View File
@@ -0,0 +1,8 @@
.. _api_DiffOps:
Differential Operators
======================
.. automodule:: SimPEG.Mesh.DiffOperators
:members:
:undoc-members:
+18
View File
@@ -0,0 +1,18 @@
.. _api_Examples:
Examples
********
.. toctree::
:maxdepth: 1
:glob:
../examples/*
External Notebooks
==================
* `Example 1: Direct Current <http://www.seogi.me/s/notebooks/DCEx.html>`_
* `Example 2: Seismic-Acoustic <http://www.seogi.me/s/notebooks/SeismicEx.html>`_
@@ -0,0 +1,27 @@
.. _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 <http://math.lanl.gov/~mac/papers/numerics/HS99B.pdf>`_). 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
@@ -0,0 +1,113 @@
.. _api_ForwardProblem:
Forward Problem
***************
Problem Class
=============
The problem is a partial differential equation of the form:
.. math::
c(m, u) = 0
Here, \\(m\\) is the model and u is the field (or fields).
Given the model, \\(m\\), we can calculate the fields \\(u(m)\\),
however, the data we collect is a subset of the fields,
and can be defined by a linear projection, \\(P\\).
.. math::
d_\text{pred} = P u(m)
For the inverse problem, we are interested in how changing the model transforms the data,
as such we can take write the Taylor expansion:
.. math::
Pu(m + hv) = Pu(m) + hP\frac{\partial u(m)}{\partial m} v + \mathcal{O}(h^2 \left\| v \right\| )
We can linearize and define the sensitivity matrix as:
.. math::
J = P\frac{\partial u}{\partial m}
The sensitivity matrix, and it's transpose will be used in the inverse problem
to (locally) find how model parameters change the data, and optimize!
Working with the general PDE, \\(c(m, u) = 0\\), where m is the model and u is the field,
the sensitivity is defined as:
.. math::
J = P\frac{\partial u}{\partial m}
We can take the derivative of the PDE:
.. math::
\nabla_m c(m, u) \partial m + \nabla_u c(m, u) \partial u = 0
If the forward problem is invertible, then we can rearrange for
\\(\\frac{\\partial u}{\\partial m}\\):
.. math::
J = - P \left( \nabla_u c(m, u) \right)^{-1} \nabla_m c(m, u)
This can often be computed given a vector (i.e. \\(J(v)\\)) rather than
stored, as \\(J\\) is a large dense matrix.
The API
=======
Problem
-------
.. autoclass:: SimPEG.Problem.BaseProblem
:members:
:undoc-members:
.. autoclass:: SimPEG.Problem.BaseTimeProblem
:members:
:undoc-members:
Fields
------
.. autoclass:: SimPEG.Fields.Fields
:members:
:undoc-members:
.. autoclass:: SimPEG.Fields.TimeFields
:members:
:undoc-members:
Survey
------
.. autoclass:: SimPEG.Survey.BaseSurvey
:members:
:undoc-members:
.. autoclass:: SimPEG.Survey.BaseSrc
:members:
:undoc-members:
.. autoclass:: SimPEG.Survey.BaseRx
:members:
:undoc-members:
.. autoclass:: SimPEG.Survey.BaseTimeRx
:members:
:undoc-members:
.. autoclass:: SimPEG.Survey.Data
:members:
:undoc-members:
+301
View File
@@ -0,0 +1,301 @@
.. _api_InnerProducts:
Inner Products
**************
By using the weak formulation of many of the PDEs in geophysical applications,
we can rapidly develop discretizations. Much of this work, however, needs a
good understanding of how to approximate inner products on our discretized
meshes. We will define the inner product as:
.. math::
\left(a,b\right) = \int_\Omega{a \cdot b}{\partial v}
where a and b are either scalars or vectors.
.. note::
The InnerProducts class is a base class providing inner product matrices
for meshes and cannot run on its own.
Example problem for DC resistivity
----------------------------------
We will start with the formulation of the Direct Current (DC) resistivity
problem in geophysics.
.. math::
\frac{1}{\sigma}\vec{j} = \nabla \phi \\
\nabla\cdot \vec{j} = q
In the following discretization, :math:`\sigma` and :math:`\phi`
will be discretized on the cell-centers and the flux, :math:`\vec{j}`,
will be on the faces. We will use the weak formulation to discretize
the DC resistivity equation.
We can define in weak form by integrating with a general face function
:math:`\vec{f}`:
.. math::
\int_{\Omega}{\sigma^{-1}\vec{j} \cdot \vec{f}} = \int_{\Omega}{\nabla \phi \cdot \vec{f}}
Here we can integrate the right side by parts,
.. math::
\nabla\cdot(\phi\vec{f})=\nabla\phi\cdot\vec{f} + \phi\nabla\cdot\vec{f}
and rearrange it, and apply the Divergence theorem.
.. math::
\int_{\Omega}{\sigma^{-1}\vec{j} \cdot \vec{f}} =
- \int_{\Omega}{(\phi \nabla \cdot \vec{f})}
+ \int_{\partial \Omega}{ \phi \vec{f} \cdot \mathbf{n}}
We can then discretize for every cell:
.. math::
v_{\text{cell}} \sigma^{-1} (\mathbf{J}_x \mathbf{F}_x +\mathbf{J}_y \mathbf{F}_y + \mathbf{J}_z \mathbf{F}_z ) = -\phi^{\top} v_{\text{cell}} \mathbf{D}_{\text{cell}} \mathbf{F} + \text{BC}
.. note::
We have discretized the dot product above, but remember that we do not
really have a single vector :math:`\mathbf{J}`, but approximations of
:math:`\vec{j}` on each face of our cell. In 2D that means 2
approximations of :math:`\mathbf{J}_x` and 2 approximations of
:math:`\mathbf{J}_y`. In 3D we also have 2 approximations of
:math:`\mathbf{J}_z`.
Regardless of how we choose to approximate this dot product, we can represent
this in vector form (again this is for every cell), and will generalize for
the case of anisotropic (tensor) sigma.
.. math::
\mathbf{F}_c^{\top} (\sqrt{v_{\text{cell}}} \Sigma^{-1} \sqrt{v_{\text{cell}}}) \mathbf{J}_c =
-\phi^{\top} v_{\text{cell}} \mathbf{D}_{\text{cell}} \mathbf{F})
+ \text{BC}
We multiply by square-root of volume on each side of the tensor conductivity
to keep symmetry in the system. Here :math:`\mathbf{J}_c` is the Cartesian
:math:`\mathbf{J}` (on the faces that we choose to use in our approximation)
and must be calculated differently depending on the mesh:
.. math::
\mathbf{J}_c = \mathbf{Q}_{(i)}\mathbf{J}_\text{TENSOR} \\
\mathbf{J}_c = \mathbf{N}_{(i)}^{-1}\mathbf{Q}_{(i)}\mathbf{J}_\text{Curv}
Here the :math:`i` index refers to where we choose to approximate this integral, as discussed in the note above.
We will approximate this integral by taking the fluxes clustered around every node of the cell, there are 8 combinations in 3D, and 4 in 2D. We will use a projection matrix :math:`\mathbf{Q}_{(i)}` to pick the appropriate fluxes. So, now that we have 8 approximations of this integral, we will just take the average. For the TensorMesh, this looks like:
.. math::
\mathbf{F}^{\top}
{1\over 8}
\left(\sum_{i=1}^8
\mathbf{Q}_{(i)}^{\top} \sqrt{v_{\text{cell}}} \Sigma^{-1} \sqrt{v_{\text{cell}}} \mathbf{Q}_{(i)}
\right)
\mathbf{J}
=
-\mathbf{F}^{\top} \mathbf{D}_{\text{cell}}^{\top} v_{\text{cell}} \phi + \text{BC}
Or, when generalizing to the entire mesh and dropping our general face function:
.. math::
\mathbf{M}^f_{\Sigma^{-1}} \mathbf{J}
=
- \mathbf{D}^{\top} \text{diag}(\mathbf{v}) \phi + \text{BC}
By defining the faceInnerProduct (8 combinations of fluxes in 3D, 4 in 2D, 2 in 1D) to be:
.. math::
\mathbf{M}^f_{\Sigma^{-1}} =
\sum_{i=1}^{2^d}
\mathbf{P}_{(i)}^{\top} \Sigma^{-1} \mathbf{P}_{(i)}
Where :math:`d` is the dimension of the mesh.
The :math:`\mathbf{M}^f` is returned when given the input of :math:`\Sigma^{-1}`.
Here each :math:`\mathbf{P} ~ \in ~ \mathbb{R}^{(d*nC, nF)}` is a combination
of the projection, volume, and any normalization to Cartesian coordinates
(where the dot product is well defined):
.. math::
\mathbf{P}_{(i)} = \sqrt{ \frac{1}{2^d} \mathbf{I}^d \otimes \text{diag}(\mathbf{v})} \overbrace{\mathbf{N}_{(i)}^{-1}}^{\text{Curv only}} \mathbf{Q}_{(i)}
.. note::
This is actually completed for each cell in the mesh at the same time, and the full matrices are returned.
If ``returnP=True`` is requested in any of these methods the projection matrices are returned as a list ordered by nodes around which the fluxes were approximated::
# In 3D
P = [P000, P100, P010, P110, P001, P101, P011, P111]
# In 2D
P = [P00, P10, P01, P11]
# In 1D
P = [P0, P1]
The derivation for ``edgeInnerProducts`` is exactly the same, however, when we
approximate the integral using the fields around each node, the projection
matrices look a bit different because we have 12 edges in 3D instead of just 6
faces. The interface to the code is exactly the same.
Defining Tensor Properties
--------------------------
**For 3D:**
Depending on the number of columns (either 1, 3, or 6) of mu, the material
property is interpreted as follows:
.. math::
\vec{\mu} = \left[\begin{matrix} \mu_{1} & 0 & 0 \\ 0 & \mu_{1} & 0 \\ 0 & 0 & \mu_{1} \end{matrix}\right]
\vec{\mu} = \left[\begin{matrix} \mu_{1} & 0 & 0 \\ 0 & \mu_{2} & 0 \\ 0 & 0 & \mu_{3} \end{matrix}\right]
\vec{\mu} = \left[\begin{matrix} \mu_{1} & \mu_{4} & \mu_{5} \\ \mu_{4} & \mu_{2} & \mu_{6} \\ \mu_{5} & \mu_{6} & \mu_{3} \end{matrix}\right]
**For 2D:**
Depending on the number of columns (either 1, 2, or 3) of mu, the material property is interpreted as follows:
.. math::
\vec{\mu} = \left[\begin{matrix} \mu_{1} & 0 \\ 0 & \mu_{1} \end{matrix}\right]
\vec{\mu} = \left[\begin{matrix} \mu_{1} & 0 \\ 0 & \mu_{2} \end{matrix}\right]
\vec{\mu} = \left[\begin{matrix} \mu_{1} & \mu_{3} \\ \mu_{3} & \mu_{2} \end{matrix}\right]
Structure of Matrices
---------------------
Both the isotropic, and anisotropic material properties result in a diagonal mass matrix.
Which is nice and easy to invert if necessary, however, in the fully anisotropic case which is not aligned with the grid, the matrix is not diagonal. This can be seen for a 3D mesh in the figure below.
.. plot::
from SimPEG import *
mesh = Mesh.TensorMesh([10,50,3])
m1 = np.random.rand(mesh.nC)
m2 = np.random.rand(mesh.nC,3)
m3 = np.random.rand(mesh.nC,6)
M = range(3)
M[0] = mesh.getFaceInnerProduct(m1)
M[1] = mesh.getFaceInnerProduct(m2)
M[2] = mesh.getFaceInnerProduct(m3)
plt.figure(figsize=(13,5))
for i, lab in enumerate(['Isotropic','Anisotropic','Tensor']):
plt.subplot(131 + i)
plt.spy(M[i],ms=0.5,color='k')
plt.tick_params(axis='both',which='both',labeltop='off',labelleft='off')
plt.title(lab + ' Material Property')
plt.show()
Taking Derivatives
------------------
We will take the derivative of the fully anisotropic tensor for a 3D mesh, the
other cases are easier and will not be discussed here. Let us start with one
part of the sum which makes up :math:`\mathbf{M}^f_\Sigma` and take the
derivative when this is multiplied by some vector :math:`\mathbf{v}`:
.. math::
\mathbf{P}^\top \boldsymbol{\Sigma} \mathbf{Pv}
Here we will let :math:`\mathbf{Pv} = \mathbf{y}` and :math:`\mathbf{y}` will have the form:
.. math::
\mathbf{y} = \mathbf{Pv} =
\left[
\begin{matrix}
\mathbf{y}_1\\
\mathbf{y}_2\\
\mathbf{y}_3\\
\end{matrix}
\right]
.. math::
\mathbf{P}^\top\Sigma\mathbf{y} =
\mathbf{P}^\top
\left[\begin{matrix}
\boldsymbol{\sigma}_{1} & \boldsymbol{\sigma}_{4} & \boldsymbol{\sigma}_{5} \\
\boldsymbol{\sigma}_{4} & \boldsymbol{\sigma}_{2} & \boldsymbol{\sigma}_{6} \\
\boldsymbol{\sigma}_{5} & \boldsymbol{\sigma}_{6} & \boldsymbol{\sigma}_{3}
\end{matrix}\right]
\left[
\begin{matrix}
\mathbf{y}_1\\
\mathbf{y}_2\\
\mathbf{y}_3\\
\end{matrix}
\right]
=
\mathbf{P}^\top
\left[
\begin{matrix}
\boldsymbol{\sigma}_{1}\circ \mathbf{y}_1 + \boldsymbol{\sigma}_{4}\circ \mathbf{y}_2 + \boldsymbol{\sigma}_{5}\circ \mathbf{y}_3\\
\boldsymbol{\sigma}_{4}\circ \mathbf{y}_1 + \boldsymbol{\sigma}_{2}\circ \mathbf{y}_2 + \boldsymbol{\sigma}_{6}\circ \mathbf{y}_3\\
\boldsymbol{\sigma}_{5}\circ \mathbf{y}_1 + \boldsymbol{\sigma}_{6}\circ \mathbf{y}_2 + \boldsymbol{\sigma}_{3}\circ \mathbf{y}_3\\
\end{matrix}
\right]
Now it is easy to take the derivative with respect to any one of the
parameters, for example,
:math:`\frac{\partial}{\partial\boldsymbol{\sigma}_1}`
.. math::
\frac{\partial}{\partial \boldsymbol{\sigma}_1}\left(\mathbf{P}^\top\Sigma\mathbf{y}\right)
=
\mathbf{P}^\top
\left[
\begin{matrix}
\text{diag}(\mathbf{y}_1)\\
0\\
0\\
\end{matrix}
\right]
Whereas :math:`\frac{\partial}{\partial\boldsymbol{\sigma}_4}`, for
example, is:
.. math::
\frac{\partial}{\partial \boldsymbol{\sigma}_4}\left(\mathbf{P}^\top\Sigma\mathbf{y}\right)
=
\mathbf{P}^\top
\left[
\begin{matrix}
\text{diag}(\mathbf{y}_2)\\
\text{diag}(\mathbf{y}_1)\\
0\\
\end{matrix}
\right]
These are computed for each of the 8 projections, horizontally concatenated,
and returned.
The API
-------
.. autoclass:: SimPEG.Mesh.InnerProducts.InnerProducts
:members:
:undoc-members:
+27
View File
@@ -0,0 +1,27 @@
InvProblem
**********
.. autoclass:: SimPEG.InvProblem.BaseInvProblem
:show-inheritance:
:members:
:undoc-members:
Inversion
*********
.. autoclass:: SimPEG.Inversion.BaseInversion
:show-inheritance:
:members:
:undoc-members:
Directives
**********
.. automodule:: SimPEG.Directives
:show-inheritance:
:members:
:undoc-members:
@@ -0,0 +1,11 @@
Inversion Components
********************
.. toctree::
:maxdepth: 3
api_DataMisfit
api_Regularization
api_Optimization
api_Inversion
+216
View File
@@ -0,0 +1,216 @@
.. _api_Maps:
SimPEG Maps
***********
That's not a map...?!
=====================
A SimPEG Map operates on a vector and transforms it to another space.
We will use an example commonly applied in electromagnetics (EM) of the
log-conductivity model.
.. math::
m = \log(\sigma)
Here we require a *mapping* to get from \\\(m\\\) to \\\(\\sigma\\\),
we will call this map \\\(\\mathcal{M}\\\).
.. math::
\sigma = \mathcal{M}(m) = \exp(m)
In SimPEG, we use a (:class:`SimPEG.Maps.ExpMap`) to describe how to map
back to conductivity. This is a relatively trivial example (we are just taking
the exponential!) but by defining maps we can start to combine and manipulate
exactly what we think about as our model, \\\(m\\\). In code, this looks like
.. code-block:: python
:linenos:
M = Mesh.TensorMesh([100]) # Create a mesh
expMap = Maps.ExpMap(M) # Create a mapping
m = np.zeros(M.nC) # Create a model vector
m[M.vectorCCx>0.5] = 1.0 # Set half of it to 1.0
sig = expMap * m # Apply the mapping using *
print m
# [ 0. 0. 0. 1. 1. 1. ]
print sig
# [ 1. 1. 1. 2.718 2.718 2.718]
Combining Maps
==============
We will use an example where we want a 1D layered earth as
our model, but we want to map this to a 2D discretization to do our forward
modeling. We will also assume that we are working in log conductivity still,
so after the transformation we want to map to conductivity space.
To do this we will introduce the vertical 1D map (:class:`SimPEG.Maps.SurjectVertical1D`),
which does the first part of what we just described. The second part will be
done by the :class:`SimPEG.Maps.ExpMap` described above.
.. code-block:: python
:linenos:
M = Mesh.TensorMesh([7,5])
v1dMap = Maps.SurjectVertical1D(M)
expMap = Maps.ExpMap(M)
myMap = expMap * v1dMap
m = np.r_[0.2,1,0.1,2,2.9] # only 5 model parameters!
sig = myMap * m
.. plot::
from SimPEG import *
import matplotlib.pyplot as plt
M = Mesh.TensorMesh([7,5])
v1dMap = Maps.SurjectVertical1D(M)
expMap = Maps.ExpMap(M)
myMap = expMap * v1dMap
m = np.r_[0.2,1,0.1,2,2.9] # only 5 model parameters!
sig = myMap * m
figs, axs = plt.subplots(1,2)
axs[0].plot(m, M.vectorCCy, 'b-o')
axs[0].set_title('Model')
axs[0].set_ylabel('Depth, y')
axs[0].set_xlabel('Value, $m_i$')
axs[0].set_xlim(0,3)
axs[0].set_ylim(0,1)
clbar = plt.colorbar(M.plotImage(sig,ax=axs[1],grid=True,gridOpts=dict(color='grey'))[0])
axs[1].set_title('Physical Property')
axs[1].set_ylabel('Depth, y')
clbar.set_label('$\sigma = \exp(\mathbf{P}m)$')
plt.tight_layout()
If you noticed, it was pretty easy to combine maps. What is even cooler is
that the derivatives also are made for you (if everything goes right).
Just to be sure that the derivative is correct, you should always run the test
on the mapping that you create.
Taking Derivatives
==================
Now that we have wrapped up the mapping, we can ensure that it is easy to take
derivatives (or at least have access to them!). In the :class:`SimPEG.Maps.ExpMap`
there are no dependencies between model parameters, so it will be a diagonal matrix:
.. math::
\left(\frac{\partial \mathcal{M}(m)}{\partial m}\right)_{ii} = \frac{\partial \exp(m_i)}{\partial m} = \exp(m_i)
Or equivalently:
.. math::
\frac{\partial \mathcal{M}(m)}{\partial m} = \text{diag}( \exp(m) )
The mapping API makes this really easy to test that you have got the derivative correct.
When these are used in the inverse problem, this is extremely important!!
.. plot::
:include-source:
from SimPEG import *
import matplotlib.pyplot as plt
M = Mesh.TensorMesh([100])
expMap = Maps.ExpMap(M)
m = np.zeros(M.nC)
m[M.vectorCCx>0.5] = 1.0
expMap.test(m, plotIt=True)
The API
=======
The :code:`IdentityMap` is the base class for all mappings, and it does absolutely nothing.
.. autoclass:: SimPEG.Maps.IdentityMap
:members:
:undoc-members:
Common Maps
===========
Exponential Map
---------------
Electrical conductivity varies over many orders of magnitude, so it is a common
technique when solving the inverse problem to parameterize and optimize in terms
of log conductivity. This makes sense not only because it ensures all conductivities
will be positive, but because this is fundamentally the space where conductivity
lives (i.e. it varies logarithmically).
.. autoclass:: SimPEG.Maps.ExpMap
:members:
:undoc-members:
Vertical 1D Map
---------------
.. autoclass:: SimPEG.Maps.SurjectVertical1D
:members:
:undoc-members:
Map 2D Cross-Section to 3D Model
--------------------------------
.. autoclass:: SimPEG.Maps.Map2Dto3D
:members:
:undoc-members:
Mesh to Mesh Map
----------------
.. plot::
from SimPEG import *
import matplotlib.pyplot as plt
M = Mesh.TensorMesh([100,100])
h1 = Utils.meshTensor([(6,7,-1.5),(6,10),(6,7,1.5)])
h1 = h1/h1.sum()
M2 = Mesh.TensorMesh([h1,h1])
V = Utils.ModelBuilder.randomModel(M.vnC, seed=79, its=50)
v = Utils.mkvc(V)
modh = Maps.Mesh2Mesh([M,M2])
modH = Maps.Mesh2Mesh([M2,M])
H = modH * v
h = modh * H
ax = plt.subplot(131)
M.plotImage(v, ax=ax)
ax.set_title('Fine Mesh (Original)')
ax = plt.subplot(132)
M2.plotImage(H,clim=[0,1],ax=ax)
ax.set_title('Course Mesh')
ax = plt.subplot(133)
M.plotImage(h,clim=[0,1],ax=ax)
ax.set_title('Fine Mesh (Interpolated)')
plt.show()
.. autoclass:: SimPEG.Maps.Mesh2Mesh
:members:
:undoc-members:
Under the Hood
==============
Combo Map
---------
The ComboMap holds the information for multiplying and combining
maps. It also uses the chain rule to create the derivative.
Remember, any time that you make your own combination of mappings
be sure to test that the derivative is correct.
.. autoclass:: SimPEG.Maps.ComboMap
:members:
:undoc-members:
+193
View File
@@ -0,0 +1,193 @@
.. _api_Mesh:
SimPEG Meshes
*************
The Mesh objects in SimPEG provide a numerical grid on which to solve
differential equations. Each mesh type has a similar API to make switching
between different meshes relatively simple.
Overview of Meshes Available
============================
The following meshes are available for use:
.. toctree::
:maxdepth: 2
api_MeshCode
Each mesh code follows the guiding principles that are present in this
tutorial, but the details, advantages and disadvantages differ between
the implementations.
.. plot::
from SimPEG import Examples
Examples.Mesh_Basic_Types.run()
Variable Locations and Terminology
==================================
We will go over the basics of using a TensorMesh, but these skills are transferable
to the other meshes available in SimPEG. All of the mesh generation code is located
in the Mesh package in SimPEG (i.e. SimPEG.Mesh).
To create a TensorMesh we need to create mesh tensors, the widths of
each cell of the mesh in each dimension. We will call these tensors h,
and these will be define the constant widths of cells in each dimension
of the TensorMesh.
.. plot::
:include-source:
from SimPEG import Mesh, np
import matplotlib.pyplot as plt
hx = np.r_[3,2,1,1,1,1,2,3]
hy = np.r_[3,1,1,3]
M = Mesh.TensorMesh([hx, hy])
M.plotGrid(centers=True)
plt.show()
In this simple mesh, the hx vector defines the widths of the cell
in the x dimension, and starts counting from the origin (0,0). The
resulting mesh is divided into cells, and the cell-centers are
plotted above as red circles. Other terminology for this mesh are:
- cell-centers
- nodes
- faces
- edges
.. plot::
:include-source:
from SimPEG import Mesh, np
import matplotlib.pyplot as plt
hx = np.r_[3,2,1,1,1,1,2,3]
hy = np.r_[3,1,1,3]
M = Mesh.TensorMesh([hx, hy])
M.plotGrid(faces=True, nodes=True)
plt.title('Cell faces in the x- and y-directions.')
plt.legend(('Nodes', 'X-Faces', 'Y-Faces'))
plt.show()
Generally, the faces are used to discretize fluxes, quantities that
leave or enter the cells. As such, these fluxes have a direction to
them, which is normal to the cell (i.e. directly out of the cell face).
The plot above shows that x-faces point in the x-direction, and
y-faces point in the y-direction. The nodes are shown in blue,
and lie at the intersection of the grid lines. In a two-dimensional
mesh, the edges actually live in the same location as the faces,
however, they align (or are tangent to) the face. This is easier to
see in 3D, when the edges do not live in the same location as the faces.
In the 3D plot below, the edge variables are seen as black triangles,
and live on the edges(!) of the cell.
.. plot::
:include-source:
from SimPEG import Mesh
Mesh.TensorMesh([1,1,1]).plotGrid(faces=True, edges=True, centers=True, showIt=True)
How many of each?
-----------------
When making variables that live in each of these locations, it is
important to know how many of each variable type you are dealing with.
SimPEG makes this pretty easy:
::
In [1]: print M
---- 2-D TensorMesh ----
x0: 0.00
y0: 0.00
nCx: 8
nCy: 4
hx: 3.00, 2.00, 4*1.00, 2.00, 3.00
hy: 3.00, 2*1.00, 3.00
In [2]: count = {'numCells': M.nC,
....: 'numCells_xDir': M.nCx,
....: 'numCells_yDir': M.nCy,
....: 'numCells_vector': M.vnC}
In [3]: print 'This mesh has %(numCells)d cells, which is %(numCells_xDir)d*%(numCells_yDir)d!!' % count
This mesh has 32 cells, which is 8*4!!
In [4]: print count
{
'numCells_vector': array([8, 4]),
'numCells_yDir': 4,
'numCells_xDir': 8,
'numCells': 32
}
SimPEG also counts the nodes, faces, and edges.
::
Nodes: M.nN, M.nNx, M.nNy, M.nNz, M.vnN
Faces: M.nF, M.nFx, M.nFy, M.nFz, M.vnF, M.vnFx, M.vnFy, M.vnFz
Edges: M.nE, M.nEx, M.nEy, M.nEz, M.vnE, M.vnEx, M.vnEy, M.vnEz
Face and edge variables have different counts depending on
the dimension of the direction that you are interested in.
In a 4x5 mesh, for example, there is a 5x5 grid of x-faces,
and a 4x6 grid of y-faces. You can count them below!
As such, the vnF(x,y,z) and vnE(x,y,z) properties give the
vector grid size.
.. plot::
:include-source:
from SimPEG import Mesh
Mesh.TensorMesh([4,5]).plotGrid(faces=True, showIt=True)
Making Tensors
--------------
For tensor meshes, there are some additional 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])
)
.. plot::
:include-source:
from SimPEG import Mesh, Utils
h1 = [(10, 5, -1.3), (5, 20), (10, 3, 1.3)]
M = Mesh.TensorMesh([h1, h1], x0='CN')
M.plotGrid(showIt=True)
.. 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.
Hopefully, you now know how to create TensorMesh objects in SimPEG,
and by extension you are also familiar with how to create and use
other types of meshes in this SimPEG framework.
The API
=======
.. autoclass:: SimPEG.Mesh.BaseMesh.BaseMesh
:members:
:undoc-members:
+68
View File
@@ -0,0 +1,68 @@
.. _api_MeshCode:
Tensor Mesh
===========
.. autoclass:: SimPEG.Mesh.TensorMesh
:members:
:undoc-members:
:show-inheritance:
Cylindrical Mesh
================
.. autoclass:: SimPEG.Mesh.CylMesh
:members:
:undoc-members:
:show-inheritance:
Tree Mesh
=========
.. autoclass:: SimPEG.Mesh.TreeMesh
:members:
:undoc-members:
:show-inheritance:
Curvilinear Mesh
================
.. autoclass:: SimPEG.Mesh.CurvilinearMesh
:members:
:undoc-members:
:show-inheritance:
Base Rectangular Mesh
=====================
.. autoclass:: SimPEG.Mesh.BaseMesh.BaseRectangularMesh
:members:
:undoc-members:
:show-inheritance:
Base Tensor Mesh
================
.. autoclass:: SimPEG.Mesh.TensorMesh.BaseTensorMesh
:members:
:undoc-members:
:show-inheritance:
Mesh IO
=======
.. automodule:: SimPEG.Mesh.MeshIO
:members:
:undoc-members:
:show-inheritance:
Mesh Viewing
============
.. automodule:: SimPEG.Mesh.View
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,9 @@
Optimize
********
.. automodule:: SimPEG.Optimization
:show-inheritance:
:private-members:
:members:
:undoc-members:
+29
View File
@@ -0,0 +1,29 @@
SimPEG PropMaps
***************
The API
=======
Property
--------
.. autoclass:: SimPEG.PropMaps.Property
:members:
:undoc-members:
PropMap
-------
.. autoclass:: SimPEG.PropMaps.PropMap
:members:
:undoc-members:
PropModel
---------
.. autoclass:: SimPEG.PropMaps.PropModel
:members:
:undoc-members:
@@ -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:
+53
View File
@@ -0,0 +1,53 @@
.. _api_Solver:
Solver
******
BYOS
====
The numerical linear algebra solver that you use will ultimately be the
bottleneck of your large scale inversion. To be the most flexible, SimPEG
provides wrappers rather than a comprehensive set of solvers (i.e. BYOS).
The interface is as follows::
A # Where A is a sparse matrix (or linear operator)
Ainv = Solver(A, **solverOpts) # Create a solver object with key word arguments
x = Ainv * b # Where b is a numpy array of shape (n,) or (n,*)
Ainv.clean() # This cleans the memory footprint (if any)
.. note::
This is somewhat an abuse of notation for solvers as we never actually
create A inverse. Instead we are creating an object that acts like A
inverse, whether that be a Krylov subspace solver or an LU decomposition.
To wrap up solvers in scipy.sparse.linalg it takes one line of code::
Solver = SolverWrapD(sp.linalg.spsolve, factorize=False)
SolverLU = SolverWrapD(sp.linalg.splu, factorize=True)
SolverCG = SolverWrapI(sp.linalg.cg)
.. note::
The above solvers are loaded into the base name space of SimPEG.
.. seealso::
- https://bitbucket.org/petsc/petsc4py
- https://github.com/bfroehle/pymumps
- https://github.com/rowanc1/pymatsolver
The API
=======
.. autofunction:: SimPEG.Utils.SolverUtils.SolverWrapD
:noindex:
.. autofunction:: SimPEG.Utils.SolverUtils.SolverWrapI
:noindex:
+8
View File
@@ -0,0 +1,8 @@
.. _api_Tests:
Testing SimPEG
==============
.. automodule:: SimPEG.Tests
:members:
:undoc-members:
+11
View File
@@ -0,0 +1,11 @@
Utilities
*********
.. toctree::
:maxdepth: 2
api_Solver
api_Maps
api_PropMaps
api_Utils
api_Tests
+92
View File
@@ -0,0 +1,92 @@
Utils
*****
.. automodule:: SimPEG.Utils
:members:
:undoc-members:
Matrix Utilities
================
.. automodule:: SimPEG.Utils.matutils
:members:
:undoc-members:
Solver Utilities
================
.. automodule:: SimPEG.Utils.SolverUtils
:members:
:undoc-members:
Curv Utilities
==============
.. automodule:: SimPEG.Utils.curvutils
:members:
:undoc-members:
Mesh Utilities
==============
.. automodule:: SimPEG.Utils.meshutils
:members:
:undoc-members:
Model Builder Utilities
=======================
.. automodule:: SimPEG.Utils.ModelBuilder
:members:
:undoc-members:
Interpolation Utilities
=======================
.. automodule:: SimPEG.Utils.interputils
:members:
:undoc-members:
Counter Utilities
=================
.. code-block:: python
:linenos:
class MyClass(object):
def __init__(self, url):
self.counter = Counter()
@count
def MyMethod(self):
pass
@timeIt
def MySecondMethod(self):
pass
c = MyClass('blah')
for i in range(100): c.MyMethod()
for i in range(300): c.MySecondMethod()
c.counter.summary()
.. code-block:: text
:linenos:
Counters:
MyClass.MyMethod : 100
Times: mean sum
MyClass.MySecondMethod : 1.70e-06, 5.10e-04, 300x
The API
-------
.. automodule:: SimPEG.Utils.CounterUtils
:members:
:undoc-members:
+69
View File
@@ -0,0 +1,69 @@
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:: ../../images/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:: ../../images/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.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.
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.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.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
+80
View File
@@ -0,0 +1,80 @@
.. _api_installing:
Getting Started with SimPEG
***************************
Dependencies
============
- Python 2.7
- NumPy 1.8 (or greater)
- SciPy 0.13 (or greater)
- matplotlib 1.3 (or greater)
- Cython 0.20 (or greater)
Installing Python
=================
Python is available on all major operating systems, but if you are getting started with python
it is best to use a package manager such as
`Continuum Anaconda <https://store.continuum.io/cshop/anaconda/>`_ or
`Enthought Canopy <https://www.enthought.com/products/canopy/>`_.
You can download the package manager and use it to install the dependencies above.
Installing SimPEG
=================
SimPEG is on pip!!::
pip install SimPEG
Installing from Source
----------------------
First (you need git)::
git clone https://github.com/simpeg/simpeg
Second (from the root of the simpeg repository)::
python setup.py install
Useful Links
============
An enormous amount of information (including tutorials and examples) can be found on the official websites of the packages
* `Python Website <http://www.python.org/>`_
* `Numpy Website <http://www.numpy.org/>`_
* `SciPy Website <http://www.scipy.org/>`_
* `Matplotlib <http://matplotlib.org/>`_
Python for scientific computing
-------------------------------
* `Python for Scientists <https://sites.google.com/site/pythonforscientists/>`_ Links to commonly used packages, Matlab to Python comparison
* `Python Wiki <http://wiki.python.org/moin/NumericAndScientific>`_ Lists packages and resources for scientific computing in Python
Numpy and Matlab
----------------
* `NumPy for Matlab Users <http://wiki.scipy.org/NumPy_for_Matlab_Users>`_
* `Python vs Matlab <https://sites.google.com/site/pythonforscientists/python-vs-matlab>`_
Lessons in Python
-----------------
* `Software Carpentry <http://software-carpentry.org/v4/python/index.html>`_
* `Introduction to NumPy and Matplotlib <http://www.youtube.com/watch?v=3Fp1zn5ao2M>`_
Editing Python
--------------
There are numerous ways to edit and test Python (see `PythonWiki <http://wiki.python.org/moin/PythonEditors>`_ for an overview) and in our group at least the following options are being used:
* `Sublime <http://www.sublimetext.com/>`_
* `iPython Notebook <http://ipython.org/notebook.html>`_
* `iPython <http://ipython.org/>`_
* `Enthought Canopy <https://www.enthought.com/products/canopy/>`_