diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 84469e3f..3ca3f780 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 0.1.10 +current_version = 0.1.11 files = setup.py SimPEG/__init__.py docs/conf.py diff --git a/.gitignore b/.gitignore index fc798cea..e1264b7d 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ nosetests.xml *.sublime-workspace docs/_build/ Makefile +docs/warnings.txt diff --git a/.travis.yml b/.travis.yml index 419c830f..d4539a4c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,18 +24,25 @@ env: - TEST_DIR=tests/examples - TEST_DIR=tests/em/fdem/inverse/adjoint - TEST_DIR=tests/em/fdem/forward + - TEST_DIR=tests/docs; + GAE_PYTHONPATH=${HOME}/.cache/google_appengine; + PATH=$PATH:${HOME}/google-cloud-sdk/bin; + PYTHONPATH=${PYTHONPATH}:${GAE_PYTHONPATH}; + CLOUDSDK_CORE_DISABLE_PROMPTS=1 # Setup anaconda before_install: - - if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then wget http://repo.continuum.io/miniconda/Miniconda-3.8.3-Linux-x86_64.sh -O miniconda.sh; else wget http://repo.continuum.io/miniconda/Miniconda3-3.8.3-Linux-x86_64.sh -O miniconda.sh; fi +# Install packages + - if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then wget http://repo.continuum.io/miniconda/Miniconda-3.8.3-Linux-x86_64.sh + -O miniconda.sh; else wget http://repo.continuum.io/miniconda/Miniconda3-3.8.3-Linux-x86_64.sh + -O miniconda.sh; fi - chmod +x miniconda.sh - ./miniconda.sh -b - export PATH=/home/travis/anaconda/bin:/home/travis/miniconda/bin:$PATH - conda update --yes conda -# Install packages install: - - conda install --yes pip python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib cython ipython nose vtk + - conda install --yes pip python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib cython ipython nose vtk sphinx - pip install nose-cov python-coveralls - git clone https://github.com/rowanc1/pymatsolver.git @@ -46,12 +53,28 @@ install: # Run test script: + # test docs - nosetests $TEST_DIR --with-cov --cov SimPEG --cov-config .coveragerc -v -s # Calculate coverage after_success: - coveralls --config_file .coveragerc + - if [ "$TRAVIS_BRANCH" = "master" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then + if [ ${TEST_DIR} == "tests/docs" ]; then + python scripts/fetch_gae_sdk.py $(dirname "${GAE_PYTHONPATH}"); + openssl aes-256-cbc -K $encrypted_93066031461c_key -iv $encrypted_93066031461c_iv + -in docs/credentials.tar.gz.enc -out credentials.tar.gz -d ; + if [ ! -d ${HOME}/google-cloud-sdk ]; then curl https://sdk.cloud.google.com | bash; fi ; + tar -xzf credentials.tar.gz ; + gcloud auth activate-service-account --key-file client-secret.json ; + gcloud config set project simpegdocs; + gcloud -q components update gae-python; + gcloud -q preview app deploy ./docs/app.yaml --version ${TRAVIS_COMMIT} --promote; + fi; + fi + + notifications: email: - rowanc1@gmail.com diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 93e51f62..69e85e84 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -144,6 +144,7 @@ class BetaSchedule(InversionDirective): if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter self.invProb.beta /= self.coolingFactor + class TargetMisfit(InversionDirective): chifact = 1. @@ -166,7 +167,7 @@ class TargetMisfit(InversionDirective): -class _SaveEveryIteration(InversionDirective): +class SaveEveryIteration(InversionDirective): @property def name(self): if getattr(self, '_name', None) is None: @@ -187,7 +188,7 @@ class _SaveEveryIteration(InversionDirective): self._fileName = value -class SaveModelEveryIteration(_SaveEveryIteration): +class SaveModelEveryIteration(SaveEveryIteration): """SaveModelEveryIteration""" def initialize(self): @@ -197,7 +198,7 @@ class SaveModelEveryIteration(_SaveEveryIteration): np.save('%03d-%s' % (self.opt.iter, self.fileName), self.opt.xc) -class SaveOutputEveryIteration(_SaveEveryIteration): +class SaveOutputEveryIteration(SaveEveryIteration): """SaveModelEveryIteration""" def initialize(self): @@ -211,7 +212,7 @@ class SaveOutputEveryIteration(_SaveEveryIteration): f.write(' %3d %1.4e %1.4e %1.4e %1.4e\n'%(self.opt.iter, self.invProb.beta, self.invProb.phi_d, self.invProb.phi_m, self.opt.f)) f.close() -class SaveOutputDictEveryIteration(_SaveEveryIteration): +class SaveOutputDictEveryIteration(SaveEveryIteration): """SaveOutputDictEveryIteration""" def initialize(self): @@ -242,12 +243,6 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # Save the file as a npz np.savez('{:03d}-{:s}'.format(self.opt.iter,self.fileName), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred) - -# class UpdateReferenceModel(Parameter): - -# mref0 = None - -# def nextIter(self): # mref = getattr(self, 'm_prev', None) # if mref is None: # if self.debug: print 'UpdateReferenceModel is using mref0' @@ -258,56 +253,138 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): class Update_IRLS(InversionDirective): eps_min = None + eps_p = None + eps_q = None + norms = [2.,2.,2.,2.] factor = None gamma = None phi_m_last = None phi_d_last = None + f_old = None + f_min_change = 1e-2 + beta_tol = 5e-2 + # Solving parameter for IRLS (mode:2) + IRLSiter = 0 + minGNiter = 5 + maxIRLSiter = 10 + iterStart = 0 + + # Beta schedule + coolingFactor = 2. + coolingRate = 1 + + mode = 1 + + @property + def target(self): + if getattr(self, '_target', None) is None: + self._target = self.survey.nD*0.5 + return self._target + @target.setter + def target(self, val): + self._target = val def initialize(self): - # Scale the regularization for changes in norm - if getattr(self, 'phi_m_last', None) is not None: - - self.reg.curModel = self.invProb.curModel - self.reg.gamma = 1. - phim_new = self.reg.eval(self.invProb.curModel) - self.gamma = self.phi_m_last / phim_new - - self.reg.curModel = self.invProb.curModel - self.reg.gamma = self.gamma - - if getattr(self, 'phi_d_last', None) is None: - self.phi_d_last = self.invProb.phi_d + if self.mode == 1: + self.reg.norms = [2., 2., 2., 2.] def endIter(self): - # Cool the threshold parameter if required - if getattr(self, 'factor', None) is not None: - eps = self.reg.eps / self.factor - if getattr(self, 'eps_min', None) is not None: - self.reg.eps = np.max([self.eps_min,eps]) + # After reaching target misfit with l2-norm, switch to IRLS (mode:2) + if self.invProb.phi_d < self.target and self.mode == 1: + print "Convergence with smooth l2-norm regularization: Start IRLS steps..." + + self.mode = 2 + print self.eps_p, self.eps_q, self.norms + self.reg.eps_p = self.eps_p + self.reg.eps_q = self.eps_q + self.reg.norms = self.norms + self.coolingFactor = 1. + self.coolingRate = 1 + self.iterStart = self.opt.iter + self.phi_d_last = self.invProb.phi_d + self.phi_m_last = self.invProb.phi_m_last + + self.reg.l2model = self.invProb.curModel + self.reg.curModel = self.invProb.curModel + + if getattr(self, 'f_old', None) is None: + self.f_old = self.reg.eval(self.invProb.curModel)#self.invProb.evalFunction(self.invProb.curModel, return_g=False, return_H=False) + + # Beta Schedule + if self.opt.iter > 0 and self.opt.iter % self.coolingRate == 0: + if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter + self.invProb.beta /= self.coolingFactor + + + # Only update after GN iterations + if (self.opt.iter-self.iterStart) % self.minGNiter == 0 and self.mode==2: + + self.IRLSiter += 1 + + phim_new = self.reg.eval(self.invProb.curModel) + self.f_change = np.abs(self.f_old - phim_new) / self.f_old + + print "Regularization decrease: %6.3e" % (self.f_change) + + # Check for maximum number of IRLS cycles + if self.IRLSiter == self.maxIRLSiter: + print "Reach maximum number of IRLS cycles: %i" % self.maxIRLSiter + self.opt.stopNextIteration = True + return + + # Check if the function has changed enough + if self.f_change < self.f_min_change and self.IRLSiter > 1: + print "Minimum decrease in regularization. End of IRLS" + self.opt.stopNextIteration = True + return else: - self.reg.eps = eps + self.f_old = phim_new - # Get phi_m at the end of current iteration - self.phi_m_last = self.invProb.phi_m_last + # Cool the threshold parameter if required + if getattr(self, 'factor', None) is not None: + eps = self.reg.eps / self.factor - # Update the model used for the IRLS weights - self.reg.curModel = self.invProb.curModel + if getattr(self, 'eps_min', None) is not None: + self.reg.eps = np.max([self.eps_min,eps]) + else: + self.reg.eps = eps - # Temporarely set gamma to 1. to get raw phi_m - self.reg.gamma = 1. + # Get phi_m at the end of current iteration + self.phi_m_last = self.invProb.phi_m_last - # Compute new model objective function value - phim_new = self.reg.eval(self.invProb.curModel) + # Reset the regularization matrices so that it is + # recalculated for current model + self.reg._Wsmall = None + self.reg._Wx = None + self.reg._Wy = None + self.reg._Wz = None - # Update gamma to scale the regularization between IRLS iterations - self.reg.gamma = self.phi_m_last / phim_new + # Update the model used for the IRLS weights + self.reg.curModel = self.invProb.curModel - # Set the weighting matrix to None so that it is recomputed next time - # it is called in the inversion - self.reg._W = None + # Temporarely set gamma to 1. to get raw phi_m + self.reg.gamma = 1. + + # Compute new model objective function value + phim_new = self.reg.eval(self.invProb.curModel) + + # Update gamma to scale the regularization between IRLS iterations + self.reg.gamma = self.phi_m_last / phim_new + + # Reset the regularization matrices again for new gamma + self.reg._Wsmall = None + self.reg._Wx = None + self.reg._Wy = None + self.reg._Wz = None + + # Check if misfit is within the tolerance, otherwise scale beta + val = self.invProb.phi_d / (self.survey.nD*0.5) + + if np.abs(1.-val) > self.beta_tol: + self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d class Update_lin_PreCond(InversionDirective): """ @@ -360,19 +437,3 @@ class Update_Wj(InversionDirective): JtJdiag = JtJdiag / max(JtJdiag) self.reg.wght = JtJdiag - -class Scale_Beta(InversionDirective): - """ - Instead of a linear cooling schedule, beta is allowed to change based - on the ratio between the target misfit and the current data misfit. The - update is done only if the misfit is outside some threshold bounds. - """ - tol = 0.05 - - def endIter(self): - - # Check if misfit is within the tolerance, otherwise adjust beta - val = self.invProb.phi_d / (self.survey.nD*0.5) - - if np.abs(1.-val) > self.tol: - self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d diff --git a/SimPEG/EM/Analytics/FDEMDipolarfields.py b/SimPEG/EM/Analytics/FDEMDipolarfields.py new file mode 100644 index 00000000..7b79a680 --- /dev/null +++ b/SimPEG/EM/Analytics/FDEMDipolarfields.py @@ -0,0 +1,302 @@ +from __future__ import division +import numpy as np +from scipy.constants import mu_0, pi, epsilon_0 +from scipy.special import erf +from SimPEG import Utils + +omega = lambda f: 2.*np.pi*f +# TODO: +# r = lambda dx, dy, dz: np.sqrt( dx**2. + dy**2. + dz**2.) +# k = lambda f, mu, epsilon, sig: np.sqrt( omega(f)**2. *mu*epsilon -1j*omega(f)*mu*sig ) + +def E_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=0., epsr=1.): + + """ + Computing Analytic Electric fields from Electrical Dipole in a Wholespace + TODO: + Add description of parameters + """ + mu = mu_0*(1+kappa) + epsilon = epsilon_0*epsr + sig_hat = sig + 1j*omega(f)*epsilon + + XYZ = Utils.asArray_N_x_Dim(XYZ, 3) + # Check + if XYZ.shape[0] > 1 & f.shape[0] > 1: + raise Exception("I/O type error: For multiple field locations only a single frequency can be specified.") + + dx = XYZ[:,0]-srcLoc[0] + dy = XYZ[:,1]-srcLoc[1] + dz = XYZ[:,2]-srcLoc[2] + + r = np.sqrt( dx**2. + dy**2. + dz**2.) + # k = np.sqrt( -1j*2.*np.pi*f*mu*sig ) + k = np.sqrt( omega(f)**2. *mu*epsilon -1j*omega(f)*mu*sig ) + + front = current * length / (4.*np.pi*sig_hat* r**3) * np.exp(-1j*k*r) + mid = -k**2 * r**2 + 3*1j*k*r + 3 + + if orientation.upper() == 'X': + Ex = front*((dx**2 / r**2)*mid + (k**2 * r**2 -1j*k*r-1.)) + Ey = front*(dx*dy / r**2)*mid + Ez = front*(dx*dz / r**2)*mid + return Ex, Ey, Ez + + elif orientation.upper() == 'Y': + # x--> y, y--> z, z-->x + Ey = front*((dy**2 / r**2)*mid + (k**2 * r**2 -1j*k*r-1.)) + Ez = front*(dy*dz / r**2)*mid + Ex = front*(dy*dx / r**2)*mid + return Ex, Ey, Ez + + elif orientation.upper() == 'Z': + # x --> z, y --> x, z --> y + Ez = front*((dz**2 / r**2)*mid + (k**2 * r**2 -1j*k*r-1.)) + Ex = front*(dz*dx / r**2)*mid + Ey = front*(dz*dy / r**2)*mid + return Ex, Ey, Ez + + +def E_galvanic_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.): + + """ + Computing Galvanic portion of Electric fields from Electrical Dipole in a Wholespace + TODO: + Add description of parameters + """ + mu = mu_0*(1+kappa) + epsilon = epsilon_0*epsr + sig_hat = sig + 1j*omega(f)*epsilon + + XYZ = Utils.asArray_N_x_Dim(XYZ, 3) + # Check + if XYZ.shape[0] > 1 & f.shape[0] > 1: + raise Exception("I/O type error: For multiple field locations only a single frequency can be specified.") + + dx = XYZ[:,0]-srcLoc[0] + dy = XYZ[:,1]-srcLoc[1] + dz = XYZ[:,2]-srcLoc[2] + + r = np.sqrt( dx**2. + dy**2. + dz**2.) + # k = np.sqrt( -1j*2.*np.pi*f*mu*sig ) + k = np.sqrt( omega(f)**2. *mu*epsilon -1j*omega(f)*mu*sig ) + + front = current * length / (4.*np.pi*sig_hat* r**3) * np.exp(-1j*k*r) + mid = -k**2 * r**2 + 3*1j*k*r + 3 + + if orientation.upper() == 'X': + Ex_galvanic = front*((dx**2 / r**2)*mid + (-1j*k*r-1.)) + Ey_galvanic = front*(dx*dy / r**2)*mid + Ez_galvanic = front*(dx*dz / r**2)*mid + return Ex_galvanic, Ey_galvanic, Ez_galvanic + + elif orientation.upper() == 'Y': + # x--> y, y--> z, z-->x + Ey_galvanic = front*((dy**2 / r**2)*mid + (-1j*k*r-1.)) + Ez_galvanic = front*(dy*dz / r**2)*mid + Ex_galvanic = front*(dy*dx / r**2)*mid + return Ex_galvanic, Ey_galvanic, Ez_galvanic + + elif orientation.upper() == 'Z': + # x --> z, y --> x, z --> y + Ez_galvanic = front*((dz**2 / r**2)*mid + (-1j*k*r-1.)) + Ex_galvanic = front*(dz*dx / r**2)*mid + Ey_galvanic = front*(dz*dy / r**2)*mid + return Ex_galvanic, Ey_galvanic, Ez_galvanic + + +def E_inductive_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.): + + """ + Computing Inductive portion of Electric fields from Electrical Dipole in a Wholespace + TODO: + Add description of parameters + """ + mu = mu_0*(1+kappa) + epsilon = epsilon_0*epsr + sig_hat = sig + 1j*omeg*epsilon + + XYZ = Utils.asArray_N_x_Dim(XYZ, 3) + # Check + if XYZ.shape[0] > 1 & f.shape[0] > 1: + raise Exception("I/O type error: For multiple field locations only a single frequency can be specified.") + + dx = XYZ[:,0]-srcLoc[0] + dy = XYZ[:,1]-srcLoc[1] + dz = XYZ[:,2]-srcLoc[2] + + r = np.sqrt( dx**2. + dy**2. + dz**2.) + # k = np.sqrt( -1j*2.*np.pi*f*mu*sig ) + k = np.sqrt( omega(f)**2. *mu*epsilon -1j*omega(f)*mu*sig ) + + front = current * length / (4.*np.pi*sig_hat* r**3) * np.exp(-1j*k*r) + + if orientation.upper() == 'X': + Ex_inductive = front*(k**2 * r**2) + Ey_inductive = np.zeros_like(Ex_inductive) + Ez_inductive = np.zeros_like(Ex_inductive) + return Ex_inductive, Ey_inductive, Ez_inductive + + elif orientation.upper() == 'Y': + # x--> y, y--> z, z-->x + Ey_inductive = front*(k**2 * r**2) + Ez_inductive = np.zeros_like(Ey_inductive) + Ex_inductive = np.zeros_like(Ey_inductive) + return Ex_inductive, Ey_inductive, Ez_inductive + + elif orientation.upper() == 'Z': + # x --> z, y --> x, z --> y + Ez_inductive = front*(k**2 * r**2) + Ex_inductive = np.zeros_like(Ez_inductive) + Ey_inductive = np.zeros_like(Ez_inductive) + return Ex_inductive, Ey_inductive, Ez_inductive + + +def J_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.): + + """ + Computing Current densities from Electrical Dipole in a Wholespace + TODO: + Add description of parameters + """ + + Ex, Ey, Ez = E_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.) + Jx = sig*Ex + Jy = sig*Ey + Jz = sig*Ez + return Jx, Jy, Jz + + +def J_galvanic_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.): + + """ + Computing Galvanic portion of Current densities from Electrical Dipole in a Wholespace + TODO: + Add description of parameters + """ + + Ex_galvanic, Ey_galvanic, Ez_galvanic = E_galvanic_from_ElectricDipoleWholeSpaced(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.) + Jx_galvanic = sig*Ex_galvanic + Jy_galvanic = sig*Ey_galvanic + Jz_galvanic = sig*Ez_galvanic + return Jx_galvanic, Jy_galvanic, Jz_galvanic + + +def J_inductive_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.): + + """ + Computing Inductive portion of Current densities from Electrical Dipole in a Wholespace + TODO: + Add description of parameters + """ + + Ex_inductive, Ey_inductive, Ez_inductive = E_inductive_from_ElectricDipoleWholeSpaced(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.) + Jx_inductive = sig*Ex_inductive + Jy_inductive = sig*Ey_inductive + Jz_inductive = sig*Ez_inductive + return Jx_inductive, Jy_inductive, Jz_inductive + + +def H_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.): + + """ + Computing Magnetic fields from Electrical Dipole in a Wholespace + TODO: + Add description of parameters + """ + mu = mu_0*(1+kappa) + epsilon = epsilon_0*epsr + XYZ = Utils.asArray_N_x_Dim(XYZ, 3) + # Check + if XYZ.shape[0] > 1 & f.shape[0] > 1: + raise Exception("I/O type error: For multiple field locations only a single frequency can be specified.") + + dx = XYZ[:,0]-srcLoc[0] + dy = XYZ[:,1]-srcLoc[1] + dz = XYZ[:,2]-srcLoc[2] + + r = np.sqrt( dx**2. + dy**2. + dz**2.) + # k = np.sqrt( -1j*2.*np.pi*f*mu*sig ) + k = np.sqrt( omega(f)**2. *mu*epsilon -1j*omega(f)*mu*sig ) + + front = current * length / (4.*np.pi* r**2) * (-1j*k*r + 1) * np.exp(-1j*k*r) + + if orientation.upper() == 'X': + Hy = front*(-dz / r) + Hz = front*(dy / r) + Hx = np.zeros_like(Hy) + return Hx, Hy, Hz + + elif orientation.upper() == 'Y': + Hx = front*(dz / r) + Hz = front*(-dx / r) + Hy = np.zeros_like(Hx) + return Hx, Hy, Hz + + elif orientation.upper() == 'Z': + Hx = front*(-dy / r) + Hy = front*(dx / r) + Hz = np.zeros_like(Hx) + return Hx, Hy, Hz + + +def B_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.): + + """ + Computing Magnetic flux densites from Electrical Dipole in a Wholespace + TODO: + Add description of parameters + """ + + Hx, Hy, Hz = H_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.) + Bx = mu*Hx + By = mu*Hy + Bz = mu*Hz + return Bx, By, Bz + + +def A_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.): + + """ + Computing Electric vector potentials from Electrical Dipole in a Wholespace + TODO: + Add description of parameters + """ + mu = mu_0*(1+kappa) + epsilon = epsilon_0*epsr + XYZ = Utils.asArray_N_x_Dim(XYZ, 3) + # Check + if XYZ.shape[0] > 1 & f.shape[0] > 1: + raise Exception("I/O type error: For multiple field locations only a single frequency can be specified.") + + dx = XYZ[:,0]-srcLoc[0] + dy = XYZ[:,1]-srcLoc[1] + dz = XYZ[:,2]-srcLoc[2] + + r = np.sqrt( dx**2. + dy**2. + dz**2.) + k = np.sqrt( omega(f)**2. *mu*epsilon -1j*omega(f)*mu*sig ) + + front = current * length / (4.*np.pi*r) + + if orientation.upper() == 'X': + Ax = front*np.exp(-1j*k*r) + Ay = np.zeros_like(Ax) + Az = np.zeros_like(Ax) + return Ax, Ay, Az + + elif orientation.upper() == 'Y': + Ay = front*np.exp(-1j*k*r) + Ax = np.zeros_like(Ay) + Az = np.zeros_like(Ay) + return Ax, Ay, Az + + elif orientation.upper() == 'Z': + Az = front*np.exp(-1j*k*r) + Ax = np.zeros_like(Ay) + Ay = np.zeros_like(Ay) + return Ax, Ay, Az + + + + + diff --git a/SimPEG/EM/Analytics/__init__.py b/SimPEG/EM/Analytics/__init__.py index 9df2aef7..8331501d 100644 --- a/SimPEG/EM/Analytics/__init__.py +++ b/SimPEG/EM/Analytics/__init__.py @@ -2,3 +2,4 @@ from TDEM import hzAnalyticDipoleT from FDEM import hzAnalyticDipoleF from FDEMcasing import * from DC import DCAnalyticHalf, DCAnalyticSphere +from FDEMDipolarfields import * diff --git a/SimPEG/EM/Base.py b/SimPEG/EM/Base.py index 2a2ce363..15a0ce60 100644 --- a/SimPEG/EM/Base.py +++ b/SimPEG/EM/Base.py @@ -20,10 +20,10 @@ class BaseEMProblem(Problem.BaseProblem): Problem.BaseProblem.__init__(self, mesh, **kwargs) - surveyPair = Survey.BaseSurvey - dataPair = Survey.Data + surveyPair = Survey.BaseSurvey #: The survey to pair with. + dataPair = Survey.Data #: The data to pair with. - PropMap = EMPropMap + PropMap = EMPropMap #: The property mapping Solver = SimpegSolver solverOpts = {} @@ -217,6 +217,7 @@ class BaseEMSurvey(Survey.BaseSurvey): def eval(self, f): """ Project fields to receiver locations + :param Fields u: fields object :rtype: numpy.ndarray :return: data diff --git a/SimPEG/EM/FDEM/FieldsFDEM.py b/SimPEG/EM/FDEM/FieldsFDEM.py index 253b9984..e0f54be2 100644 --- a/SimPEG/EM/FDEM/FieldsFDEM.py +++ b/SimPEG/EM/FDEM/FieldsFDEM.py @@ -6,11 +6,11 @@ from SimPEG.EM.Utils import omega from SimPEG.Utils import Zero, Identity, sdiag -class Fields(SimPEG.Problem.Fields): +class FieldsFDEM(SimPEG.Problem.Fields): """ Fancy Field Storage for a FDEM survey. Only one field type is stored for - each problem, the rest are computed. The fields obejct acts like an array and is indexed by + each problem, the rest are computed. The fields object acts like an array and is indexed by .. code-block:: python @@ -92,7 +92,7 @@ class Fields(SimPEG.Problem.Fields): """ Total derivative of e with respect to the inversion model. Returns :math:`d\mathbf{e}/d\mathbf{m}` for forward and (:math:`d\mathbf{e}/d\mathbf{u}`, :math:`d\mathb{u}/d\mathbf{m}`) for the adjoint - :param Src src: sorce + :param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: source :param numpy.ndarray du_dm_v: derivative of the solution vector with respect to the model times a vector (is None for adjoint) :param numpy.ndarray v: vector to take sensitivity product with :param bool adjoint: adjoint? @@ -110,7 +110,7 @@ class Fields(SimPEG.Problem.Fields): """ Total derivative of b with respect to the inversion model. Returns :math:`d\mathbf{b}/d\mathbf{m}` for forward and (:math:`d\mathbf{b}/d\mathbf{u}`, :math:`d\mathb{u}/d\mathbf{m}`) for the adjoint - :param Src src: sorce + :param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: source :param numpy.ndarray du_dm_v: derivative of the solution vector with respect to the model times a vector (is None for adjoint) :param numpy.ndarray v: vector to take sensitivity product with :param bool adjoint: adjoint? @@ -128,7 +128,7 @@ class Fields(SimPEG.Problem.Fields): """ Total derivative of h with respect to the inversion model. Returns :math:`d\mathbf{h}/d\mathbf{m}` for forward and (:math:`d\mathbf{h}/d\mathbf{u}`, :math:`d\mathb{u}/d\mathbf{m}`) for the adjoint - :param Src src: sorce + :param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: source :param numpy.ndarray du_dm_v: derivative of the solution vector with respect to the model times a vector (is None for adjoint) :param numpy.ndarray v: vector to take sensitivity product with :param bool adjoint: adjoint? @@ -146,7 +146,7 @@ class Fields(SimPEG.Problem.Fields): """ Total derivative of j with respect to the inversion model. Returns :math:`d\mathbf{j}/d\mathbf{m}` for forward and (:math:`d\mathbf{j}/d\mathbf{u}`, :math:`d\mathb{u}/d\mathbf{m}`) for the adjoint - :param Src src: sorce + :param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: source :param numpy.ndarray du_dm_v: derivative of the solution vector with respect to the model times a vector (is None for adjoint) :param numpy.ndarray v: vector to take sensitivity product with :param bool adjoint: adjoint? @@ -160,12 +160,12 @@ class Fields(SimPEG.Problem.Fields): return self._jDeriv_u(src, v, adjoint), self._jDeriv_m(src, v, adjoint) return np.array(self._jDeriv_u(src, du_dm_v, adjoint) + self._jDeriv_m(src, v, adjoint), dtype = complex) -class Fields3D_e(Fields): +class Fields3D_e(FieldsFDEM): """ Fields object for Problem3D_e. - :param Mesh mesh: mesh - :param Survey survey: survey + :param BaseMesh mesh: mesh + :param SimPEG.EM.FDEM.SurveyFDEM.Survey survey: survey """ knownFields = {'eSolution':'E'} @@ -180,9 +180,6 @@ class Fields3D_e(Fields): 'h' : ['eSolution','CCV','_h'], } - def __init__(self, mesh, survey, **kwargs): - Fields.__init__(self, mesh, survey, **kwargs) - def startup(self): self.prob = self.survey.prob self._edgeCurl = self.survey.prob.mesh.edgeCurl @@ -426,12 +423,12 @@ class Fields3D_e(Fields): -class Fields3D_b(Fields): +class Fields3D_b(FieldsFDEM): """ Fields object for Problem3D_b. - :param Mesh mesh: mesh - :param Survey survey: survey + :param BaseMesh mesh: mesh + :param SimPEG.EM.FDEM.SurveyFDEM.Survey survey: survey """ knownFields = {'bSolution':'F'} @@ -446,9 +443,6 @@ class Fields3D_b(Fields): 'h' : ['bSolution','CCV','_h'], } - def __init__(self,mesh,survey,**kwargs): - Fields.__init__(self,mesh,survey,**kwargs) - def startup(self): self.prob = self.survey.prob self._edgeCurl = self.survey.prob.mesh.edgeCurl @@ -693,12 +687,12 @@ class Fields3D_b(Fields): return Zero() -class Fields3D_j(Fields): +class Fields3D_j(FieldsFDEM): """ Fields object for Problem3D_j. - :param Mesh mesh: mesh - :param Survey survey: survey + :param BaseMesh mesh: mesh + :param SimPEG.EM.FDEM.SurveyFDEM.Survey survey: survey """ knownFields = {'jSolution':'F'} @@ -713,9 +707,6 @@ class Fields3D_j(Fields): 'b' : ['jSolution','CCV','_b'], } - def __init__(self,mesh,survey,**kwargs): - Fields.__init__(self,mesh,survey,**kwargs) - def startup(self): self.prob = self.survey.prob self._edgeCurl = self.survey.prob.mesh.edgeCurl @@ -988,12 +979,12 @@ class Fields3D_j(Fields): return 1./(1j * omega(src.freq)) * VI * (self._aveE2CCV * ( s_mDeriv(v) - self._edgeCurl.T * ( self._MfRhoDeriv(jSolution) * v ) ) ) -class Fields3D_h(Fields): +class Fields3D_h(FieldsFDEM): """ Fields object for Problem3D_h. - :param Mesh mesh: mesh - :param Survey survey: survey + :param BaseMesh mesh: mesh + :param SimPEG.EM.FDEM.SurveyFDEM.Survey survey: survey """ knownFields = {'hSolution':'E'} @@ -1008,9 +999,6 @@ class Fields3D_h(Fields): 'b' : ['hSolution','CCV','_b'], } - def __init__(self,mesh,survey,**kwargs): - Fields.__init__(self,mesh,survey,**kwargs) - def startup(self): self.prob = self.survey.prob self._edgeCurl = self.survey.prob.mesh.edgeCurl diff --git a/SimPEG/EM/FDEM/ProblemFDEM.py b/SimPEG/EM/FDEM/ProblemFDEM.py index 9eb2e915..cbc01b9e 100644 --- a/SimPEG/EM/FDEM/ProblemFDEM.py +++ b/SimPEG/EM/FDEM/ProblemFDEM.py @@ -1,7 +1,7 @@ from SimPEG import Problem, Utils, np, sp, Solver as SimpegSolver from scipy.constants import mu_0 from SurveyFDEM import Survey as SurveyFDEM -from FieldsFDEM import Fields, Fields3D_e, Fields3D_b, Fields3D_h, Fields3D_j +from FieldsFDEM import FieldsFDEM, Fields3D_e, Fields3D_b, Fields3D_h, Fields3D_j from SimPEG.EM.Base import BaseEMProblem from SimPEG.EM.Utils import omega @@ -31,10 +31,11 @@ class BaseFDEMProblem(BaseEMProblem): if using the H-J formulation (:code:`Problem3D_j` or :code:`Problem3D_h`). Note that here, :math:`\mathbf{s_m}` is an integrated quantity. The problem performs the elimination so that we are solving the system for \\\(\\\mathbf{e},\\\mathbf{b},\\\mathbf{j} \\\) or \\\(\\\mathbf{h}\\\) + """ surveyPair = SurveyFDEM - fieldsPair = Fields + fieldsPair = FieldsFDEM def fields(self, m): """ @@ -64,7 +65,7 @@ class BaseFDEMProblem(BaseEMProblem): :param numpy.array m: inversion model (nP,) :param numpy.array v: vector which we take sensitivity product with (nP,) - :param SimPEG.EM.FDEM.Fields u: fields object + :param SimPEG.EM.FDEM.FieldsFDEM.FieldsFDEM u: fields object :rtype numpy.array: :return: Jv (ndata,) """ @@ -99,7 +100,7 @@ class BaseFDEMProblem(BaseEMProblem): :param numpy.array m: inversion model (nP,) :param numpy.array v: vector which we take adjoint product with (nP,) - :param SimPEG.EM.FDEM.Fields u: fields object + :param SimPEG.EM.FDEM.FieldsFDEM.FieldsFDEM u: fields object :rtype numpy.array: :return: Jv (ndata,) """ @@ -153,8 +154,8 @@ class BaseFDEMProblem(BaseEMProblem): Evaluates the sources for a given frequency and puts them in matrix form :param float freq: Frequency - :rtype: (numpy.ndarray, numpy.ndarray) - :return: s_m, s_e (nE or nF, nSrc) + :rtype: tuple + :return: (s_m, s_e) (nE or nF, nSrc) """ Srcs = self.survey.getSrcByFreq(freq) if self._formulation is 'EB': @@ -194,7 +195,7 @@ class Problem3D_e(BaseFDEMProblem): which we solve for :math:`\mathbf{e}`. - :param SimPEG.Mesh mesh: mesh + :param SimPEG.Mesh.BaseMesh.BaseMesh mesh: mesh """ _solutionType = 'eSolution' @@ -269,7 +270,7 @@ class Problem3D_e(BaseFDEMProblem): Derivative of the right hand side with respect to the model :param float freq: frequency - :param SimPEG.EM.FDEM.Src src: FDEM source + :param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source :param numpy.ndarray v: vector to take product with :param bool adjoint: adjoint? :rtype: numpy.ndarray @@ -305,7 +306,7 @@ class Problem3D_b(BaseFDEMProblem): .. note :: The inverse problem will not work with full anisotropy - :param SimPEG.Mesh mesh: mesh + :param SimPEG.Mesh.BaseMesh.BaseMesh mesh: mesh """ _solutionType = 'bSolution' @@ -400,7 +401,7 @@ class Problem3D_b(BaseFDEMProblem): Derivative of the right hand side with respect to the model :param float freq: frequency - :param SimPEG.EM.FDEM.Src src: FDEM source + :param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source :param numpy.ndarray v: vector to take product with :param bool adjoint: adjoint? :rtype: numpy.ndarray @@ -444,6 +445,7 @@ class Problem3D_j(BaseFDEMProblem): \mathbf{h} = \\frac{1}{i \omega} \mathbf{M_{\mu}^e}^{-1} \\left(-\mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{j} + \mathbf{M^e} \mathbf{s_m} \\right) + and solve for \\\(\\\mathbf{j}\\\) using .. math :: @@ -453,7 +455,7 @@ class Problem3D_j(BaseFDEMProblem): .. note:: This implementation does not yet work with full anisotropy!! - :param SimPEG.Mesh mesh: mesh + :param SimPEG.Mesh.BaseMesh.BaseMesh mesh: mesh """ _solutionType = 'jSolution' @@ -529,8 +531,8 @@ class Problem3D_j(BaseFDEMProblem): \mathbf{RHS} = \mathbf{C} \mathbf{M_{\mu}^e}^{-1}\mathbf{s_m} -i\omega \mathbf{s_e} :param float freq: Frequency - :rtype: numpy.ndarray (nE, nSrc) - :return: RHS + :rtype: numpy.ndarray + :return: RHS (nE, nSrc) """ s_m, s_e = self.getSourceTerm(freq) @@ -549,7 +551,7 @@ class Problem3D_j(BaseFDEMProblem): Derivative of the right hand side with respect to the model :param float freq: frequency - :param SimPEG.EM.FDEM.Src src: FDEM source + :param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source :param numpy.ndarray v: vector to take product with :param bool adjoint: adjoint? :rtype: numpy.ndarray @@ -591,7 +593,7 @@ class Problem3D_h(BaseFDEMProblem): \\left(\mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{C} + i \omega \mathbf{M_{\mu}^e}\\right) \mathbf{h} = \mathbf{M^e} \mathbf{s_m} + \mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{s_e} - :param SimPEG.Mesh mesh: mesh + :param SimPEG.Mesh.BaseMesh.BaseMesh mesh: mesh """ _solutionType = 'hSolution' @@ -608,9 +610,11 @@ class Problem3D_h(BaseFDEMProblem): .. math:: \mathbf{A} = \mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{C} + i \omega \mathbf{M_{\mu}^e} + :param float freq: Frequency :rtype: scipy.sparse.csr_matrix :return: A + """ MeMu = self.MeMu @@ -653,6 +657,7 @@ class Problem3D_h(BaseFDEMProblem): :param float freq: Frequency :rtype: numpy.ndarray :return: RHS (nE, nSrc) + """ s_m, s_e = self.getSourceTerm(freq) @@ -666,7 +671,7 @@ class Problem3D_h(BaseFDEMProblem): Derivative of the right hand side with respect to the model :param float freq: frequency - :param SimPEG.EM.FDEM.Src src: FDEM source + :param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source :param numpy.ndarray v: vector to take product with :param bool adjoint: adjoint? :rtype: numpy.ndarray diff --git a/SimPEG/EM/FDEM/RxFDEM.py b/SimPEG/EM/FDEM/RxFDEM.py index 53d6c722..13e2f291 100644 --- a/SimPEG/EM/FDEM/RxFDEM.py +++ b/SimPEG/EM/FDEM/RxFDEM.py @@ -25,10 +25,10 @@ class BaseRx(SimPEG.Survey.BaseRx): def eval(self, src, mesh, f): """ - Project fields to recievers to get data. + Project fields to receivers to get data. - :param Source src: FDEM source - :param Mesh mesh: mesh used + :param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source + :param BaseMesh mesh: mesh used :param Fields f: fields object :rtype: numpy.ndarray :return: fields projected to recievers @@ -44,8 +44,8 @@ class BaseRx(SimPEG.Survey.BaseRx): """ Derivative of projected fields with respect to the inversion model times a vector. - :param Source src: FDEM source - :param Mesh mesh: mesh used + :param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source + :param BaseMesh mesh: mesh used :param Fields f: fields object :param numpy.ndarray v: vector to multiply :rtype: numpy.ndarray diff --git a/SimPEG/EM/FDEM/SrcFDEM.py b/SimPEG/EM/FDEM/SrcFDEM.py index e6c8f005..7557ada7 100644 --- a/SimPEG/EM/FDEM/SrcFDEM.py +++ b/SimPEG/EM/FDEM/SrcFDEM.py @@ -23,8 +23,8 @@ class BaseSrc(Survey.BaseSrc): - :math:`s_m` : magnetic source term - :math:`s_e` : electric source term - :param Problem prob: FDEM Problem - :rtype: (numpy.ndarray, numpy.ndarray) + :param BaseFDEMProblem prob: FDEM Problem + :rtype: tuple :return: tuple with magnetic source term and electric source term """ s_m = self.s_m(prob) @@ -37,10 +37,10 @@ class BaseSrc(Survey.BaseSrc): - :code:`s_mDeriv` : derivative of the magnetic source term - :code:`s_eDeriv` : derivative of the electric source term - :param Problem prob: FDEM Problem + :param BaseFDEMProblem prob: FDEM Problem :param numpy.ndarray v: vector to take product with :param bool adjoint: adjoint? - :rtype: (numpy.ndarray, numpy.ndarray) + :rtype: tuple :return: tuple with magnetic source term and electric source term derivatives times a vector """ if v is not None: @@ -52,7 +52,7 @@ class BaseSrc(Survey.BaseSrc): """ Primary magnetic flux density - :param Problem prob: FDEM Problem + :param BaseFDEMProblem prob: FDEM Problem :rtype: numpy.ndarray :return: primary magnetic flux density """ @@ -64,7 +64,7 @@ class BaseSrc(Survey.BaseSrc): """ Primary magnetic field - :param Problem prob: FDEM Problem + :param BaseFDEMProblem prob: FDEM Problem :rtype: numpy.ndarray :return: primary magnetic field """ @@ -76,7 +76,7 @@ class BaseSrc(Survey.BaseSrc): """ Primary electric field - :param Problem prob: FDEM Problem + :param BaseFDEMProblem prob: FDEM Problem :rtype: numpy.ndarray :return: primary electric field """ @@ -88,7 +88,7 @@ class BaseSrc(Survey.BaseSrc): """ Primary current density - :param Problem prob: FDEM Problem + :param BaseFDEMProblem prob: FDEM Problem :rtype: numpy.ndarray :return: primary current density """ @@ -100,7 +100,7 @@ class BaseSrc(Survey.BaseSrc): """ Magnetic source term - :param Problem prob: FDEM Problem + :param BaseFDEMProblem prob: FDEM Problem :rtype: numpy.ndarray :return: magnetic source term on mesh """ @@ -110,7 +110,7 @@ class BaseSrc(Survey.BaseSrc): """ Electric source term - :param Problem prob: FDEM Problem + :param BaseFDEMProblem prob: FDEM Problem :rtype: numpy.ndarray :return: electric source term on mesh """ @@ -120,7 +120,7 @@ class BaseSrc(Survey.BaseSrc): """ Derivative of magnetic source term with respect to the inversion model - :param Problem prob: FDEM Problem + :param BaseFDEMProblem prob: FDEM Problem :param numpy.ndarray v: vector to take product with :param bool adjoint: adjoint? :rtype: numpy.ndarray @@ -133,7 +133,7 @@ class BaseSrc(Survey.BaseSrc): """ Derivative of electric source term with respect to the inversion model - :param Problem prob: FDEM Problem + :param BaseFDEMProblem prob: FDEM Problem :param numpy.ndarray v: vector to take product with :param bool adjoint: adjoint? :rtype: numpy.ndarray @@ -162,7 +162,7 @@ class RawVec_e(BaseSrc): """ Electric source term - :param Problem prob: FDEM Problem + :param BaseFDEMProblem prob: FDEM Problem :rtype: numpy.ndarray :return: electric source term on mesh """ @@ -191,7 +191,7 @@ class RawVec_m(BaseSrc): """ Magnetic source term - :param Problem prob: FDEM Problem + :param BaseFDEMProblem prob: FDEM Problem :rtype: numpy.ndarray :return: magnetic source term on mesh """ @@ -220,7 +220,7 @@ class RawVec(BaseSrc): """ Magnetic source term - :param Problem prob: FDEM Problem + :param BaseFDEMProblem prob: FDEM Problem :rtype: numpy.ndarray :return: magnetic source term on mesh """ @@ -232,7 +232,7 @@ class RawVec(BaseSrc): """ Electric source term - :param Problem prob: FDEM Problem + :param BaseFDEMProblem prob: FDEM Problem :rtype: numpy.ndarray :return: electric source term on mesh """ @@ -301,7 +301,7 @@ class MagDipole(BaseSrc): """ The primary magnetic flux density from a magnetic vector potential - :param Problem prob: FDEM problem + :param BaseFDEMProblem prob: FDEM problem :rtype: numpy.ndarray :return: primary magnetic field """ @@ -339,7 +339,7 @@ class MagDipole(BaseSrc): """ The primary magnetic field from a magnetic vector potential - :param Problem prob: FDEM problem + :param BaseFDEMProblem prob: FDEM problem :rtype: numpy.ndarray :return: primary magnetic field """ @@ -350,7 +350,7 @@ class MagDipole(BaseSrc): """ The magnetic source term - :param Problem prob: FDEM problem + :param BaseFDEMProblem prob: FDEM problem :rtype: numpy.ndarray :return: primary magnetic field """ @@ -364,7 +364,7 @@ class MagDipole(BaseSrc): """ The electric source term - :param Problem prob: FDEM problem + :param BaseFDEMProblem prob: FDEM problem :rtype: numpy.ndarray :return: primary magnetic field """ @@ -416,7 +416,7 @@ class MagDipole_Bfield(BaseSrc): """ The primary magnetic flux density from the analytic solution for magnetic fields from a dipole - :param Problem prob: FDEM problem + :param BaseFDEMProblem prob: FDEM problem :rtype: numpy.ndarray :return: primary magnetic field """ @@ -455,7 +455,7 @@ class MagDipole_Bfield(BaseSrc): """ The primary magnetic field from a magnetic vector potential - :param Problem prob: FDEM problem + :param BaseFDEMProblem prob: FDEM problem :rtype: numpy.ndarray :return: primary magnetic field """ @@ -466,7 +466,7 @@ class MagDipole_Bfield(BaseSrc): """ The magnetic source term - :param Problem prob: FDEM problem + :param BaseFDEMProblem prob: FDEM problem :rtype: numpy.ndarray :return: primary magnetic field """ @@ -479,7 +479,7 @@ class MagDipole_Bfield(BaseSrc): """ The electric source term - :param Problem prob: FDEM problem + :param BaseFDEMProblem prob: FDEM problem :rtype: numpy.ndarray :return: primary magnetic field """ @@ -530,7 +530,7 @@ class CircularLoop(BaseSrc): """ The primary magnetic flux density from a magnetic vector potential - :param Problem prob: FDEM problem + :param BaseFDEMProblem prob: FDEM problem :rtype: numpy.ndarray :return: primary magnetic field """ @@ -567,7 +567,7 @@ class CircularLoop(BaseSrc): """ The primary magnetic field from a magnetic vector potential - :param Problem prob: FDEM problem + :param BaseFDEMProblem prob: FDEM problem :rtype: numpy.ndarray :return: primary magnetic field """ @@ -578,7 +578,7 @@ class CircularLoop(BaseSrc): """ The magnetic source term - :param Problem prob: FDEM problem + :param BaseFDEMProblem prob: FDEM problem :rtype: numpy.ndarray :return: primary magnetic field """ @@ -591,7 +591,7 @@ class CircularLoop(BaseSrc): """ The electric source term - :param Problem prob: FDEM problem + :param BaseFDEMProblem prob: FDEM problem :rtype: numpy.ndarray :return: primary magnetic field """ diff --git a/SimPEG/EM/TDEM/BaseTDEM.py b/SimPEG/EM/TDEM/BaseTDEM.py index 15fc19e3..cb93ab40 100644 --- a/SimPEG/EM/TDEM/BaseTDEM.py +++ b/SimPEG/EM/TDEM/BaseTDEM.py @@ -112,7 +112,7 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem): """ :param numpy.array m: Conductivity model :param numpy.ndarray v: vector (model object) - :param simpegEM.TDEM.FieldsTDEM f: Fields resulting from m + :param FieldsTDEM f: Fields resulting from m :rtype: numpy.ndarray :return: w (data object) @@ -136,8 +136,8 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem): def Jtvec(self, m, v, f=None): """ :param numpy.array m: Conductivity model - :param numpy.ndarray,SimPEG.Survey.Data v: vector (data object) - :param simpegEM.TDEM.FieldsTDEM u: Fields resulting from m + :param numpy.ndarray v: vector (or a :class:`SimPEG.Survey.Data` object) + :param FieldsTDEM u: Fields resulting from m :rtype: numpy.ndarray :return: w (model object) diff --git a/SimPEG/EM/TDEM/TDEM_b.py b/SimPEG/EM/TDEM/TDEM_b.py index cd38660c..f88066e0 100644 --- a/SimPEG/EM/TDEM/TDEM_b.py +++ b/SimPEG/EM/TDEM/TDEM_b.py @@ -87,8 +87,8 @@ class ProblemTDEM_b(BaseTDEMProblem): """ :param numpy.array m: Conductivity model :param numpy.array vec: vector (like a model) - :param simpegEM.TDEM.FieldsTDEM u: Fields resulting from m - :rtype: simpegEM.TDEM.FieldsTDEM + :param FieldsTDEM u: Fields resulting from m + :rtype: FieldsTDEM :return: f Multiply G by a vector @@ -125,9 +125,9 @@ class ProblemTDEM_b(BaseTDEMProblem): """ :param numpy.array m: Conductivity model :param numpy.array vec: vector (like a fields) - :param simpegEM.TDEM.FieldsTDEM u: Fields resulting from m - :rtype: np.ndarray (like a model) - :return: p + :param FieldsTDEM u: Fields resulting from m + :rtype: numpy.ndarray + :return: p (like a model) Multiply G.T by a vector """ @@ -153,8 +153,8 @@ class ProblemTDEM_b(BaseTDEMProblem): def solveAh(self, m, p): """ :param numpy.array m: Conductivity model - :param simpegEM.TDEM.FieldsTDEM p: Fields object - :rtype: simpegEM.TDEM.FieldsTDEM + :param FieldsTDEM p: Fields object + :rtype: FieldsTDEM :return: y Solve the block-matrix system \\\(\\\hat{A} \\\hat{y} = \\\hat{p}\\\): @@ -200,8 +200,8 @@ class ProblemTDEM_b(BaseTDEMProblem): def solveAht(self, m, p): """ :param numpy.array m: Conductivity model - :param simpegEM.TDEM.FieldsTDEM p: Fields object - :rtype: simpegEM.TDEM.FieldsTDEM + :param FieldsTDEM p: Fields object + :rtype: FieldsTDEM :return: y Solve the block-matrix system \\\(\\\hat{A}^\\\\top \\\hat{y} = \\\hat{p}\\\): @@ -270,8 +270,8 @@ class ProblemTDEM_b(BaseTDEMProblem): def _AhVec(self, m, vec): """ :param numpy.array m: Conductivity model - :param simpegEM.TDEM.FieldsTDEM vec: Fields object - :rtype: simpegEM.TDEM.FieldsTDEM + :param FieldsTDEM vec: Fields object + :rtype: FieldsTDEM :return: f Multiply the matrix \\\(\\\hat{A}\\\) by a fields vector where @@ -315,8 +315,8 @@ class ProblemTDEM_b(BaseTDEMProblem): def _AhtVec(self, m, vec): """ :param numpy.array m: Conductivity model - :param simpegEM.TDEM.FieldsTDEM vec: Fields object - :rtype: simpegEM.TDEM.FieldsTDEM + :param FieldsTDEM vec: Fields object + :rtype: FieldsTDEM :return: f Multiply the matrix \\\(\\\hat{A}\\\) by a fields vector where diff --git a/SimPEG/Examples/DC_Analytic_Dipole.py b/SimPEG/Examples/DC_Analytic_Dipole.py index aed5eed4..ba999fa3 100644 --- a/SimPEG/Examples/DC_Analytic_Dipole.py +++ b/SimPEG/Examples/DC_Analytic_Dipole.py @@ -1,5 +1,5 @@ from SimPEG import * -import SimPEG.DCIP as DC +import SimPEG.EM.Static.DC as DC def run(plotIt=False): cs = 25. @@ -21,10 +21,10 @@ def run(plotIt=False): # ax.plot(xyz_rxP[:,0],xyz_rxP[:,1], 'w.') # ax.plot(xyz_rxN[:,0],xyz_rxN[:,1], 'r.', ms = 3) - rx = DC.RxDipole(xyz_rxP, xyz_rxN) - src = DC.SrcDipole([rx], [-200, 0, -12.5], [+200, 0, -12.5]) - survey = DC.SurveyDC([src]) - problem = DC.ProblemDC_CC(mesh) + rx = DC.Rx.Dipole(xyz_rxP, xyz_rxN) + src = DC.Src.Dipole([rx], np.r_[-200, 0, -12.5], np.r_[+200, 0, -12.5]) + survey = DC.Survey([src]) + problem = DC.Problem3D_CC(mesh) problem.pair(survey) try: from pymatsolver import MumpsSolver diff --git a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py index 930b452a..3e0b308c 100644 --- a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py +++ b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py @@ -19,10 +19,13 @@ def run(plotIt=True): Morrison Casing Model, and the results are used in a 2016 SEG abstract by Yang et al. - - Schenkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. + .. code-block:: text + + Schenkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. The model consists of: + - Air: Conductivity 1e-8 S/m, above z = 0 - Background: conductivity 1e-2 S/m, below z = 0 - Casing: conductivity 1e6 S/m @@ -215,7 +218,7 @@ def run(plotIt=True): # ------------ Problem and Survey --------------- survey = FDEM.Survey(sg_p + dg_p) mapping = [('sigma', Maps.IdentityMap(mesh))] - problem = FDEM.Problem3D_h(mesh, mapping=mapping) + problem = FDEM.Problem3D_h(mesh, mapping=mapping, Solver=solver) problem.pair(survey) # ------------- Solve --------------------------- diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index 06ef4be4..afd90525 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -1,7 +1,7 @@ from SimPEG import * -def run(N=200, plotIt=True): +def run(N=100, plotIt=True): """ Inversion: Linear Problem ========================= @@ -18,6 +18,8 @@ def run(N=200, plotIt=True): mesh = Mesh.TensorMesh([N]) m0 = np.ones(mesh.nC) * 1e-4 + mref = np.zeros(mesh.nC) + nk = 10 jk = np.linspace(1.,nk,nk) p = -2. @@ -50,57 +52,47 @@ def run(N=200, plotIt=True): wr = np.sum(prob.G**2.,axis=0)**0.5 wr = ( wr/np.max(wr) ) - reg = Regularization.Simple(mesh) - reg.wght = wr - +# reg = Regularization.Simple(mesh) +# reg.mref = mref +# reg.cell_weights = wr +# dmis = DataMisfit.l2_DataMisfit(survey) dmis.Wd = 1./wd - - opt = Optimization.ProjectedGNCG(maxIter=30,lower=-2.,upper=2., maxIterCG= 20, tolCG = 1e-4) - invProb = InvProblem.BaseInvProblem(dmis, reg, opt) - invProb.curModel = m0 - - beta = Directives.BetaSchedule(coolingFactor=2, coolingRate=1) - target = Directives.TargetMisfit() - +# +# opt = Optimization.ProjectedGNCG(maxIter=20,lower=-2.,upper=2., maxIterCG= 10, tolCG = 1e-4) +# invProb = InvProblem.BaseInvProblem(dmis, reg, opt) +# invProb.curModel = m0 +# +# beta = Directives.BetaSchedule(coolingFactor=2, coolingRate=1) +# target = Directives.TargetMisfit() +# betaest = Directives.BetaEstimate_ByEig() - inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest, target]) - - - mrec = inv.run(m0) - ml2 = mrec - print "Final misfit:" + str(invProb.dmisfit.eval(mrec)) - - # Switch regularization to sparse - phim = invProb.phi_m_last - phid = invProb.phi_d +# inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest, target]) +# +# +# mrec = inv.run(m0) +# ml2 = mrec +# print "Final misfit:" + str(invProb.dmisfit.eval(mrec)) +# +# # Switch regularization to sparse +# phim = invProb.phi_m_last +# phid = invProb.phi_d reg = Regularization.Sparse(mesh) + reg.mref = mref + reg.cell_weights = wr -#============================================================================== -# fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2)) -# dmdx = reg.mesh.cellDiffxStencil * mrec -# plt.plot(np.sort(dmdx)) -#============================================================================== - - #reg.recModel = mrec - reg.wght = np.ones(mesh.nC) reg.mref = np.zeros(mesh.nC) - reg.eps_p = 5e-2 - reg.eps_q = 1e-2 - reg.norms = [0., 0., 2., 2.] - reg.wght = wr + eps_p = 5e-2 + eps_q = 5e-2 + norms = [0., 0., 2., 2.] - opt = Optimization.ProjectedGNCG(maxIter=10 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 20, tolCG = 1e-3) - invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta = invProb.beta*2.) - beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1) - #betaest = Directives.BetaEstimate_ByEig() - target = Directives.TargetMisfit() - IRLS =Directives.Update_IRLS( phi_m_last = phim, phi_d_last = phid ) + opt = Optimization.ProjectedGNCG(maxIter=100 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 10, tolCG = 1e-3) + invProb = InvProblem.BaseInvProblem(dmis, reg, opt) + update_Jacobi = Directives.Update_lin_PreCond() + IRLS = Directives.Update_IRLS( norms=norms, eps_p=eps_p, eps_q=eps_q) - inv = Inversion.BaseInversion(invProb, directiveList=[beta,IRLS]) - - m0 = mrec + inv = Inversion.BaseInversion(invProb, directiveList=[IRLS,betaest,update_Jacobi]) # Run inversion mrec = inv.run(m0) @@ -117,7 +109,7 @@ def run(N=200, plotIt=True): axes[0].set_title('Columns of matrix G') axes[1].plot(mesh.vectorCCx, mtrue, 'b-') - axes[1].plot(mesh.vectorCCx, ml2, 'r-') + axes[1].plot(mesh.vectorCCx, reg.l2model, 'r-') #axes[1].legend(('True Model', 'Recovered Model')) axes[1].set_ylim(-1.0,1.25) diff --git a/SimPEG/Examples/MT_1D_ForwardAndInversion.py b/SimPEG/Examples/MT_1D_ForwardAndInversion.py index 69cedd98..446613e5 100644 --- a/SimPEG/Examples/MT_1D_ForwardAndInversion.py +++ b/SimPEG/Examples/MT_1D_ForwardAndInversion.py @@ -7,7 +7,7 @@ import matplotlib.pyplot as plt def run(plotIt=True): """ MT: 1D: Inversion - ======================= + ================= Forward model 1D MT data. Setup and run a MT 1D inversion. @@ -50,7 +50,7 @@ def run(plotIt=True): m_0 = np.log(sigma_0[active]) # Set the mapping - actMap = simpeg.Maps.ActiveCells(m1d, active, np.log(1e-8), nC=m1d.nCx) + actMap = simpeg.Maps.InjectActiveCells(m1d, active, np.log(1e-8), nC=m1d.nCx) mappingExpAct = simpeg.Maps.ExpMap(m1d) * actMap ## Setup the layout of the survey, set the sources and the connected receivers @@ -76,7 +76,7 @@ def run(plotIt=True): survey.dobs = survey.dtrue + 0.025*abs(survey.dtrue)*np.random.randn(*survey.dtrue.shape) if plotIt: - fig = MT.Utils.dataUtils.plotMT1DModelData(problem) + fig = MT.Utils.dataUtils.plotMT1DModelData(problem, [m_0]) fig.suptitle('Target - smooth true') diff --git a/SimPEG/Examples/MT_3D_Foward.py b/SimPEG/Examples/MT_3D_Foward.py index da16eeee..1d0db148 100644 --- a/SimPEG/Examples/MT_3D_Foward.py +++ b/SimPEG/Examples/MT_3D_Foward.py @@ -12,7 +12,7 @@ except: def run(plotIt=True, nFreq=1): """ MT: 3D: Forward - ======================= + =============== Forward model 3D MT data. @@ -46,16 +46,15 @@ def run(plotIt=True, nFreq=1): survey = MT.Survey(srcList) ## Setup the problem object - problem = MT.Problem3D.eForm_ps(M, sigmaPrimary=sigBG) + problem = MT.Problem3D.eForm_ps(M, sigmaPrimary=sigBG, Solver=Solver) problem.pair(survey) - problem.Solver = Solver # Calculate the data fields = problem.fields(sig) dataVec = survey.eval(fields) # Make the data - mtData = MT.Data(survey,dataVec) + mtData = MT.Data(survey, dataVec) # Add plots if plotIt: pass diff --git a/SimPEG/Examples/Utils_surface2ind_topo.py b/SimPEG/Examples/Utils_surface2ind_topo.py index 4ed1cdaf..e4f748cb 100644 --- a/SimPEG/Examples/Utils_surface2ind_topo.py +++ b/SimPEG/Examples/Utils_surface2ind_topo.py @@ -2,8 +2,12 @@ from SimPEG import * from SimPEG.Utils import surface2ind_topo -def run(plotIt=False, nx = 5, ny = 5): +def run(plotIt=False, nx=5, ny=5): """ + + Utils: surface2ind_topo + ======================= + Here we show how to use :code:`Utils.surface2ind_topo` to identify cells below a topographic surface. @@ -13,27 +17,25 @@ def run(plotIt=False, nx = 5, ny = 5): xtopo = np.linspace(mesh.gridN[:,0].min(), mesh.gridN[:,0].max()) topo = 0.4*np.sin(xtopo*5) # define a topographic surface - Topo = np.hstack([Utils.mkvc(xtopo,2),Utils.mkvc(topo,2)]) #make it an array + Topo = np.hstack([Utils.mkvc(xtopo,2), Utils.mkvc(topo,2)]) #make it an array - indcc = surface2ind_topo(mesh, Topo,'CC') + indcc = surface2ind_topo(mesh, Topo, 'CC') if plotIt: from matplotlib.pylab import plt from scipy.interpolate import interp1d - fig, ax = plt.subplots(1,1,figsize=(6,6)) + fig, ax = plt.subplots(1,1, figsize=(6,6)) mesh.plotGrid(ax=ax, nodes=True, centers=True) ax.plot(xtopo,topo,'k',linewidth=1) - # ax.plot(mesh.vectorNx, interp1d(xtopo,topo)(mesh.vectorNx),'--k',linewidth=3) ax.plot(mesh.vectorCCx, interp1d(xtopo,topo)(mesh.vectorCCx),'--k',linewidth=3) - aveN2CC = Utils.sdiag(mesh.aveN2CC.T.sum(1))*mesh.aveN2CC.T a = aveN2CC * indcc a[a > 0] = 1. a[a < 0.25] = np.nan a = a.reshape(mesh.vnN, order='F') masked_array = np.ma.array(a, mask=np.isnan(a)) - ax.pcolor(mesh.vectorNx,mesh.vectorNy,masked_array.T, cmap = plt.cm.gray,alpha=0.2) + ax.pcolor(mesh.vectorNx,mesh.vectorNy,masked_array.T, cmap=plt.cm.gray, alpha=0.2) plt.show() diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index 3c771f77..2ee4eb6d 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -38,7 +38,7 @@ if __name__ == '__main__': # Create the examples dir in the docs folder. fName = os.path.realpath(__file__) - docExamplesDir = os.path.sep.join(fName.split(os.path.sep)[:-3] + ['docs', 'examples']) + docExamplesDir = os.path.sep.join(fName.split(os.path.sep)[:-3] + ['docs', 'content', 'examples']) shutil.rmtree(docExamplesDir) os.makedirs(docExamplesDir) @@ -95,12 +95,12 @@ if __name__ == '__main__': from SimPEG import Examples Examples.%s.run() -.. literalinclude:: ../../SimPEG/Examples/%s.py +.. 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'])) + rst = os.path.sep.join((filePath.split(os.path.sep)[:-3] + ['docs', 'content', 'examples', name + '.rst'])) print 'Creating: %s.rst'%name f = open(rst, 'w') diff --git a/SimPEG/FLOW/Richards/Empirical.py b/SimPEG/FLOW/Richards/Empirical.py index 1bb163b5..c6624e94 100644 --- a/SimPEG/FLOW/Richards/Empirical.py +++ b/SimPEG/FLOW/Richards/Empirical.py @@ -31,7 +31,7 @@ class NonLinearMap(object): """ :param numpy.array u: fields :param numpy.array m: model - :rtype: scipy.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: derivative of transformed model The *transform* changes the model into the physical property. @@ -44,7 +44,7 @@ class NonLinearMap(object): """ :param numpy.array u: fields :param numpy.array m: model - :rtype: scipy.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: derivative of transformed model The *transform* changes the model into the physical property. diff --git a/SimPEG/MT/SrcMT.py b/SimPEG/MT/SrcMT.py index 70698c88..138d161f 100644 --- a/SimPEG/MT/SrcMT.py +++ b/SimPEG/MT/SrcMT.py @@ -86,7 +86,7 @@ class polxy_1Dprimary(BaseMTSrc): Get the electrical field source """ e_p = self.ePrimary(problem) - Map_sigma_p = Maps.Vertical1DMap(problem.mesh) + Map_sigma_p = Maps.SurjectVertical1D(problem.mesh) sigma_p = Map_sigma_p._transform(self.sigma1d) # Make mass matrix # Note: M(sig) - M(sig_p) = M(sig - sig_p) @@ -163,7 +163,7 @@ class polxy_3Dprimary(BaseMTSrc): Get the electrical field source """ e_p = self.ePrimary(problem) - Map_sigma_p = Maps.Vertical1DMap(problem.mesh) + Map_sigma_p = Maps.SurjectVertical1D(problem.mesh) sigma_p = Map_sigma_p._transform(self.sigma1d) # Make mass matrix # Note: M(sig) - M(sig_p) = M(sig - sig_p) diff --git a/SimPEG/MT/Utils/dataUtils.py b/SimPEG/MT/Utils/dataUtils.py index b1947cb8..614470d9 100644 --- a/SimPEG/MT/Utils/dataUtils.py +++ b/SimPEG/MT/Utils/dataUtils.py @@ -19,7 +19,7 @@ def getAppRes(MTdata): zList.append(zc) return [appResPhs(zList[i][0],np.sum(zList[i][1:3])) for i in np.arange(len(zList))] -def rotateData(MTdata,rotAngle): +def rotateData(MTdata, rotAngle): ''' Function that rotates clockwist by rotAngle (- negative for a counter-clockwise rotation) ''' @@ -44,19 +44,19 @@ def rotateData(MTdata,rotAngle): return MT.Data.fromRecArray(outRec) -def appResPhs(freq,z): +def appResPhs(freq, z): app_res = ((1./(8e-7*np.pi**2))/freq)*np.abs(z)**2 app_phs = np.arctan2(z.imag,z.real)*(180/np.pi) return app_res, app_phs -def skindepth(rho,freq): +def skindepth(rho, freq): ''' Function to calculate the skindepth of EM waves''' return np.sqrt( (rho*((1/(freq * mu_0 * np.pi ))))) -def rec2ndarr(x,dt=float): +def rec2ndarr(x, dt=float): return x.view((dt, len(x.dtype.names))) -def makeAnalyticSolution(mesh,model,elev,freqs): +def makeAnalyticSolution(mesh, model, elev, freqs): from SimPEG import MT data1D = [] for freq in freqs: @@ -70,7 +70,7 @@ def makeAnalyticSolution(mesh,model,elev,freqs): dataRec = np.array(data1D,dtype=[('freq',float),('x',float),('y',float),('z',float),('zyx',complex)]) return dataRec -def plotMT1DModelData(problem,models,symList=None): +def plotMT1DModelData(problem, models, symList=None): from SimPEG import MT # Setup the figure fontSize = 15 diff --git a/SimPEG/Maps.py b/SimPEG/Maps.py index 3e97499f..ecfd51e1 100644 --- a/SimPEG/Maps.py +++ b/SimPEG/Maps.py @@ -41,8 +41,8 @@ class IdentityMap(object): If this is a meshless mapping (i.e. nP is defined independently) the shape will be the the shape (nP,nP). - :rtype: (int,int) - :return: shape of the operator as a tuple + :rtype: tuple + :return: shape of the operator as a tuple (int,int) """ if self._nP is not None: return (self.nP, self.nP) @@ -86,7 +86,7 @@ class IdentityMap(object): The derivative of the transformation. :param numpy.array m: model - :rtype: scipy.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: derivative of transformed model """ @@ -216,7 +216,7 @@ class ExpMap(IdentityMap): def deriv(self, m): """ :param numpy.array m: model - :rtype: scipy.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: derivative of transformed model The *transform* changes the model into the physical property. @@ -366,7 +366,7 @@ class SurjectVertical1D(IdentityMap): def deriv(self, m): """ :param numpy.array m: model - :rtype: scipy.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: derivative of transformed model """ repNum = self.mesh.vnC[:self.mesh.dim-1].prod() @@ -427,7 +427,7 @@ class Surject2Dto3D(IdentityMap): def deriv(self, m): """ :param numpy.array m: model - :rtype: scipy.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: derivative of transformed model """ inds = self * np.arange(self.nP) diff --git a/SimPEG/Mesh/BaseMesh.py b/SimPEG/Mesh/BaseMesh.py index 14b3aecf..97394b68 100644 --- a/SimPEG/Mesh/BaseMesh.py +++ b/SimPEG/Mesh/BaseMesh.py @@ -7,8 +7,8 @@ class BaseMesh(object): BaseMesh does all the counting you don't want to do. BaseMesh should be inherited by meshes with a regular structure. - :param numpy.array,list n: number of cells in each direction (dim, ) - :param numpy.array,list x0: Origin of the mesh (dim, ) + :param numpy.array n: (or list) number of cells in each direction (dim, ) + :param numpy.array x0: (or list) Origin of the mesh (dim, ) """ @@ -34,8 +34,8 @@ class BaseMesh(object): """ Origin of the mesh - :rtype: numpy.array (dim, ) - :return: x0 + :rtype: numpy.array + :return: x0, (dim, ) """ return self._x0 @@ -116,8 +116,8 @@ class BaseMesh(object): """ Total number of edges in each direction - :rtype: numpy.array (dim, ) - :return: [nEx, nEy, nEz] + :rtype: numpy.array + :return: [nEx, nEy, nEz], (dim, ) .. plot:: :include-source: @@ -173,8 +173,8 @@ class BaseMesh(object): """ Total number of faces in each direction - :rtype: numpy.array (dim, ) - :return: [nFx, nFy, nFz] + :rtype: numpy.array + :return: [nFx, nFy, nFz], (dim, ) .. plot:: :include-source: @@ -200,8 +200,8 @@ class BaseMesh(object): """ Face Normals - :rtype: numpy.array (sum(nF), dim) - :return: normals + :rtype: numpy.array + :return: normals, (sum(nF), dim) """ if self.dim == 2: nX = np.c_[np.ones(self.nFx), np.zeros(self.nFx)] @@ -218,8 +218,8 @@ class BaseMesh(object): """ Edge Tangents - :rtype: numpy.array (sum(nE), dim) - :return: normals + :rtype: numpy.array + :return: normals, (sum(nE), dim) """ if self.dim == 2: tX = np.c_[np.ones(self.nEx), np.zeros(self.nEx)] @@ -236,8 +236,9 @@ class BaseMesh(object): Given a vector, fV, in cartesian coordinates, this will project it onto the mesh using the normals :param numpy.array fV: face vector with shape (nF, dim) - :rtype: numpy.array with shape (nF, ) - :return: projected face vector + :rtype: numpy.array + :return: projected face vector, (nF, ) + """ assert isinstance(fV, np.ndarray), 'fV must be an ndarray' assert len(fV.shape) == 2 and fV.shape[0] == self.nF and fV.shape[1] == self.dim, 'fV must be an ndarray of shape (nF x dim)' @@ -248,8 +249,9 @@ class BaseMesh(object): Given a vector, eV, in cartesian coordinates, this will project it onto the mesh using the tangents :param numpy.array eV: edge vector with shape (nE, dim) - :rtype: numpy.array with shape (nE, ) - :return: projected edge vector + :rtype: numpy.array + :return: projected edge vector, (nE, ) + """ assert isinstance(eV, np.ndarray), 'eV must be an ndarray' assert len(eV.shape) == 2 and eV.shape[0] == self.nE and eV.shape[1] == self.dim, 'eV must be an ndarray of shape (nE x dim)' @@ -295,7 +297,7 @@ class BaseRectangularMesh(BaseMesh): """ Total number of cells in each direction - :rtype: numpy.array (dim, ) + :rtype: numpy.array :return: [nCx, nCy, nCz] """ return np.array([x for x in [self.nCx, self.nCy, self.nCz] if not x is None]) @@ -335,7 +337,7 @@ class BaseRectangularMesh(BaseMesh): """ Total number of nodes in each direction - :rtype: numpy.array (dim, ) + :rtype: numpy.array :return: [nNx, nNy, nNz] """ return np.array([x for x in [self.nNx, self.nNy, self.nNz] if not x is None]) @@ -345,7 +347,7 @@ class BaseRectangularMesh(BaseMesh): """ Number of x-edges in each direction - :rtype: numpy.array (dim, ) + :rtype: numpy.array :return: vnEx """ return np.array([x for x in [self.nCx, self.nNy, self.nNz] if not x is None]) @@ -355,7 +357,7 @@ class BaseRectangularMesh(BaseMesh): """ Number of y-edges in each direction - :rtype: numpy.array (dim, ) + :rtype: numpy.array :return: vnEy or None if dim < 2 """ return None if self.dim < 2 else np.array([x for x in [self.nNx, self.nCy, self.nNz] if not x is None]) @@ -365,7 +367,7 @@ class BaseRectangularMesh(BaseMesh): """ Number of z-edges in each direction - :rtype: numpy.array (dim, ) + :rtype: numpy.array :return: vnEz or None if dim < 3 """ return None if self.dim < 3 else np.array([x for x in [self.nNx, self.nNy, self.nCz] if not x is None]) @@ -375,7 +377,7 @@ class BaseRectangularMesh(BaseMesh): """ Number of x-faces in each direction - :rtype: numpy.array (dim, ) + :rtype: numpy.array :return: vnFx """ return np.array([x for x in [self.nNx, self.nCy, self.nCz] if not x is None]) @@ -385,7 +387,7 @@ class BaseRectangularMesh(BaseMesh): """ Number of y-faces in each direction - :rtype: numpy.array (dim, ) + :rtype: numpy.array :return: vnFy or None if dim < 2 """ return None if self.dim < 2 else np.array([x for x in [self.nCx, self.nNy, self.nCz] if not x is None]) @@ -395,7 +397,7 @@ class BaseRectangularMesh(BaseMesh): """ Number of z-faces in each direction - :rtype: numpy.array (dim, ) + :rtype: numpy.array :return: vnFz or None if dim < 3 """ return None if self.dim < 3 else np.array([x for x in [self.nCx, self.nCy, self.nNz] if not x is None]) diff --git a/SimPEG/Mesh/CylMesh.py b/SimPEG/Mesh/CylMesh.py index f0b6751e..f1258184 100644 --- a/SimPEG/Mesh/CylMesh.py +++ b/SimPEG/Mesh/CylMesh.py @@ -68,8 +68,8 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView): """ Number of x-faces in each direction - :rtype: numpy.array (dim, ) - :return: vnFx + :rtype: numpy.array + :return: vnFx, (dim, ) """ return self.vnC @@ -78,8 +78,8 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView): """ Number of y-edges in each direction - :rtype: numpy.array (dim, ) - :return: vnEy or None if dim < 2 + :rtype: numpy.array + :return: vnEy or None if dim < 2, (dim, ) """ nNx = self.nNx if self.isSymmetric else self.nNx - 1 return np.r_[nNx, self.nCy, self.nNz] @@ -89,8 +89,8 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView): """ Number of z-edges in each direction - :rtype: numpy.array (dim, ) - :return: vnEz or None if nCy > 1 + :rtype: numpy.array + :return: vnEz or None if nCy > 1, (dim, ) """ if self.isSymmetric: return np.r_[self.nNx, self.nNy, self.nCz] diff --git a/SimPEG/Mesh/InnerProducts.py b/SimPEG/Mesh/InnerProducts.py index 42a08702..0c08cdd3 100644 --- a/SimPEG/Mesh/InnerProducts.py +++ b/SimPEG/Mesh/InnerProducts.py @@ -16,7 +16,7 @@ class InnerProducts(object): :param bool invProp: inverts the material property :param bool invMat: inverts the matrix :param bool doFast: do a faster implementation if available. - :rtype: scipy.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: M, the inner product matrix (nF, nF) """ return self._getInnerProduct('F', prop=prop, invProp=invProp, invMat=invMat, doFast=doFast) @@ -27,7 +27,7 @@ class InnerProducts(object): :param bool invProp: inverts the material property :param bool invMat: inverts the matrix :param bool doFast: do a faster implementation if available. - :rtype: scipy.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: M, the inner product matrix (nE, nE) """ return self._getInnerProduct('E', prop=prop, invProp=invProp, invMat=invMat, doFast=doFast) @@ -39,7 +39,7 @@ class InnerProducts(object): :param bool invProp: inverts the material property :param bool invMat: inverts the matrix :param bool doFast: do a faster implementation if available. - :rtype: scipy.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: M, the inner product matrix (nE, nE) """ assert projType in ['F', 'E'], "projType must be 'F' for faces or 'E' for edges" @@ -115,13 +115,12 @@ class InnerProducts(object): :param bool doFast: do a faster implementation if available. :param bool invProp: inverts the material property :param bool invMat: inverts the matrix - :rtype: function :return: dMdmu(u), the derivative of the inner product matrix (u) Given u, dMdmu returns (nF, nC*nA) - :param np.ndarray u: vector that multiplies dMdmu - :rtype: scipy.csr_matrix + :param numpy.ndarray u: vector that multiplies dMdmu + :rtype: scipy.sparse.csr_matrix :return: dMdmu, the derivative of the inner product matrix for a certain u """ return self._getInnerProductDeriv(prop, 'F', doFast=doFast, invProp=invProp, invMat=invMat) @@ -133,7 +132,7 @@ class InnerProducts(object): :param bool doFast: do a faster implementation if available. :param bool invProp: inverts the material property :param bool invMat: inverts the matrix - :rtype: scipy.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: dMdm, the derivative of the inner product matrix (nE, nC*nA) """ return self._getInnerProductDeriv(prop, 'E', doFast=doFast, invProp=invProp, invMat=invMat) @@ -145,7 +144,7 @@ class InnerProducts(object): :param bool doFast: do a faster implementation if available. :param bool invProp: inverts the material property :param bool invMat: inverts the matrix - :rtype: scipy.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: dMdm, the derivative of the inner product matrix (nE, nC*nA) """ fast = None @@ -169,7 +168,7 @@ class InnerProducts(object): :param numpy.array v: vector to multiply (required in the general implementation) :param list P: list of projection matrices :param str projType: 'F' for faces 'E' for edges - :rtype: scipy.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: dMdm, the derivative of the inner product matrix (n, nC*nA) """ assert projType in ['F', 'E'], "projType must be 'F' for faces or 'E' for edges" diff --git a/SimPEG/Mesh/MeshIO.py b/SimPEG/Mesh/MeshIO.py index 1c042237..0810f973 100644 --- a/SimPEG/Mesh/MeshIO.py +++ b/SimPEG/Mesh/MeshIO.py @@ -6,13 +6,11 @@ class TensorMeshIO(object): @classmethod def readUBC(TensorMesh, fileName): """ - Read UBC GIF 3DTensor mesh and generate 3D Tensor mesh in simpegTD + Read UBC GIF 3D tensor mesh and generate 3D TensorMesh in SimPEG. - Input: - :param fileName, path to the UBC GIF mesh file - - Output: - :param SimPEG TensorMesh object + :param string fileName: path to the UBC GIF mesh file + :rtype: TensorMesh + :return: The tensor mesh for the fileName. """ # Interal function to read cell size lines for the UBC mesh files. @@ -48,11 +46,9 @@ class TensorMeshIO(object): Read VTK Rectilinear (vtr xml file) and return SimPEG Tensor mesh and model Input: - :param vtrFileName, path to the vtr model file to write to - - Output: - :return SimPEG TensorMesh object - :return SimPEG model dictionary + :param string fileName: path to the vtr model file to read + :rtype: tuple + :return: (TensorMesh, modelDictionary) """ # Import @@ -102,9 +98,8 @@ class TensorMeshIO(object): Makes and saves a VTK rectilinear file (vtr) for a simpeg Tensor mesh and model. Input: - :param str, path to the output vtk file - :param mesh, SimPEG TensorMesh object - mesh to be transfer to VTK - :param models, dictionary of numpy.array - Name('s) and array('s). Match number of cells + :param string fileName: path to the output vtk file + :param dict models: dictionary of numpy.array - Name('s) and array('s). Match number of cells """ # Import @@ -162,12 +157,9 @@ class TensorMeshIO(object): """ Read UBC 3DTensor mesh model and generate 3D Tensor mesh model in simpeg - Input: - :param fileName, path to the UBC GIF mesh file to read - :param mesh, TensorMesh object, mesh that coresponds to the model - - Output: - :return numpy array, model with TensorMesh ordered + :param string fileName: path to the UBC GIF mesh file to read + :rtype: numpy.ndarray + :return: model with TensorMesh ordered """ f = open(fileName, 'r') model = np.array(map(float, f.readlines())) @@ -183,8 +175,7 @@ class TensorMeshIO(object): Writes a model associated with a SimPEG TensorMesh to a UBC-GIF format model file. - :param str fileName: File to write to - :param simpeg.Mesh.TensorMesh mesh: The mesh + :param string fileName: File to write to :param numpy.ndarray model: The model """ @@ -201,8 +192,8 @@ class TensorMeshIO(object): """ Writes a SimPEG TensorMesh to a UBC-GIF format mesh file. - :param str fileName: File to write to - :param simpeg.Mesh.TensorMesh mesh: The mesh + :param string fileName: File to write to + :param dict models: A dictionary of the models """ assert mesh.dim == 3 @@ -231,9 +222,8 @@ class TreeMeshIO(object): """ Write UBC ocTree mesh and model files from a simpeg ocTree mesh and model. - :param str fileName: File to write to - :param simpeg.Mesh.TreeMesh mesh: The mesh - :param dictionary models: The models in a dictionary, where the keys is the name of the of the model file + :param string fileName: File to write to + :param dict models: The models in a dictionary, where the keys is the name of the of the model file """ # Calculate information to write in the file. @@ -286,10 +276,9 @@ class TreeMeshIO(object): Input: :param str meshFile: path to the UBC GIF OcTree mesh file to read + :rtype: SimPEG.Mesh.TreeMesh + :return: The octree mesh - Output: - :return SimPEG.Mesh.TreeMesh mesh: The octree mesh - :return list of ndarray's: models as a list of numpy array's """ ## Read the file lines @@ -335,11 +324,9 @@ class TreeMeshIO(object): """ Read UBC OcTree model and get vector - Input: - :param fileName, path to the UBC GIF model file to read - - Output: - :return numpy array, OcTree model + :param string fileName: path to the UBC GIF model file to read + :rtype: numpy.ndarray + :return: OcTree model """ if type(fileName) is list: diff --git a/SimPEG/Mesh/TensorMesh.py b/SimPEG/Mesh/TensorMesh.py index 1650b5cb..65b6d7e9 100644 --- a/SimPEG/Mesh/TensorMesh.py +++ b/SimPEG/Mesh/TensorMesh.py @@ -198,8 +198,8 @@ class BaseTensorMesh(BaseMesh): Determines if a set of points are inside a mesh. :param numpy.ndarray pts: Location of points to test - :rtype numpy.ndarray - :return inside, numpy array of booleans + :rtype numpy.ndarray: + :return: inside, numpy array of booleans """ pts = Utils.asArray_N_x_Dim(pts, self.dim) @@ -221,7 +221,7 @@ class BaseTensorMesh(BaseMesh): :param numpy.ndarray loc: Location of points to interpolate to :param str locType: What to interpolate (see below) - :rtype: scipy.sparse.csr.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: M, the interpolation matrix locType can be:: @@ -289,7 +289,7 @@ class BaseTensorMesh(BaseMesh): :param bool returnP: returns the projection matrices :param bool invProp: inverts the material property :param bool invMat: inverts the matrix - :rtype: scipy.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: M, the inner product matrix (nF, nF) """ assert projType in ['F', 'E'], "projType must be 'F' for faces or 'E' for edges" diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 2c75fda1..d994e3a5 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -1875,7 +1875,7 @@ class TreeMesh(BaseTensorMesh, InnerProducts, TreeMeshIO): :param numpy.ndarray locs: Location of points to interpolate to :param str locType: What to interpolate (see below) - :rtype: scipy.sparse.csr.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: M, the interpolation matrix locType can be:: diff --git a/SimPEG/Optimization.py b/SimPEG/Optimization.py index 77704733..c66242aa 100644 --- a/SimPEG/Optimization.py +++ b/SimPEG/Optimization.py @@ -131,7 +131,7 @@ class Minimize(object): Minimizes the function (evalFunction) starting at the location x0. - :param def evalFunction: function handle that evaluates: f, g, H = F(x) + :param callable evalFunction: function handle that evaluates: f, g, H = F(x) :param numpy.ndarray x0: starting location :rtype: numpy.ndarray :return: x, the last iterate of the optimization algorithm @@ -372,8 +372,8 @@ class Minimize(object): Else, a modifySearchDirectionBreak call is preformed. :param numpy.ndarray p: searchDirection - :rtype: numpy.ndarray,bool - :return: (xt, passLS) + :rtype: tuple + :return: (xt, passLS) numpy.ndarray, bool """ # Projected Armijo linesearch self._LS_t = 1 @@ -408,8 +408,8 @@ class Minimize(object): evalFunction returns a False indicating the break was not caught. :param numpy.ndarray p: searchDirection - :rtype: numpy.ndarray,bool - :return: (xt, breakCaught) + :rtype: tuple + :return: (xt, breakCaught) numpy.ndarray, bool """ self.printDone(inLS=True) print 'The linesearch got broken. Boo.' @@ -1008,4 +1008,4 @@ class ProjectedGNCG(BFGS, Minimize, Remember): indx = ((self.xc<=self.lower) & (delx < 0)) | ((self.xc>=self.upper) & (delx > 0)) delx[indx] = 0. - return delx + return delx \ No newline at end of file diff --git a/SimPEG/PropMaps.py b/SimPEG/PropMaps.py index e4f65973..34cad863 100644 --- a/SimPEG/PropMaps.py +++ b/SimPEG/PropMaps.py @@ -187,7 +187,7 @@ class _PropMapMetaClass(type): attrs[attr + 'Model'] = prop._getModelProperty() attrs[attr + 'Deriv'] = prop._getModelDerivProperty() - return type(name.replace('PropMap', 'PropModel'), (PropModel, ), attrs) + return type('PropModel', (PropModel, ), attrs) class PropMap(object): diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index fc101a61..2ce5614c 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -1,4 +1,6 @@ -import Utils, Maps, Mesh, numpy as np, scipy.sparse as sp +import Utils, Maps, Mesh +import numpy as np +import scipy.sparse as sp class RegularizationMesh(object): """ @@ -8,7 +10,7 @@ class RegularizationMesh(object): are not necessarily true differential operators, but are constructed from a SimPEG Mesh. - :param Mesh mesh: problem mesh + :param BaseMesh mesh: problem mesh :param numpy.array indActive: bool array, size nC, that is True where we have active cells. Used to reduce the operators so we regularize only on active cells """ @@ -381,8 +383,8 @@ class BaseRegularization(object): :param numpy.array m: geophysical model :param numpy.array v: vector to multiply - :rtype: scipy.sparse.csr_matrix or numpy.ndarray - :return: WtW or WtW*v + :rtype: scipy.sparse.csr_matrix + :return: WtW, or if v is supplied WtW*v (numpy.ndarray) The regularization is: @@ -403,7 +405,238 @@ class BaseRegularization(object): return mD.T * ( self.W.T * ( self.W * ( mD * v) ) ) -class Tikhonov(BaseRegularization): +class Simple(BaseRegularization): + """ + Simple regularization that does not include length scales in the derivatives. + """ + + mrefInSmooth = False #: include mref in the smoothness? + alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Wsmall'], "Smallness weight") + alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") + alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") + alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") + cell_weights = 1. + + def __init__(self, mesh, mapping=None, indActive=None, **kwargs): + BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) + + if isinstance(self.cell_weights,float): + self.cell_weights = np.ones(self.regmesh.nC) * self.cell_weights + + @property + def Wsmall(self): + """Regularization matrix Wsmall""" + if getattr(self,'_Wsmall', None) is None: + self._Wsmall = Utils.sdiag((self.alpha_s*self.cell_weights)**0.5) + return self._Wsmall + + @property + def Wx(self): + """Regularization matrix Wx""" + if getattr(self, '_Wx', None) is None: + self._Wx = Utils.sdiag((self.alpha_x * (self.regmesh.aveCC2Fx*self.cell_weights))**0.5)*self.regmesh.cellDiffxStencil + return self._Wx + + @property + def Wy(self): + """Regularization matrix Wy""" + if getattr(self, '_Wy', None) is None: + self._Wy = Utils.sdiag((self.alpha_y * (self.regmesh.aveCC2Fy*self.cell_weights))**0.5)*self.regmesh.cellDiffyStencil + return self._Wy + + @property + def Wz(self): + """Regularization matrix Wz""" + if getattr(self, '_Wz', None) is None: + self._Wz = Utils.sdiag((self.alpha_z * (self.regmesh.aveCC2Fz*self.cell_weights))**0.5)*self.regmesh.cellDiffzStencil + return self._Wz + +# @property +# def Wsmooth(self): +# """Full smoothness regularization matrix W""" +# print 'wtf why are we using Wsmooth' +# raise NotImplementedError +# if getattr(self, '_Wsmooth', None) is None: +# wlist = (self.Wx,) +# if self.regmesh.dim > 1: +# wlist += (self.Wy,) +# if self.regmesh.dim > 2: +# wlist += (self.Wz,) +# self._Wsmooth = sp.vstack(wlist) +# return self._Wsmooth +# +# @property +# def W(self): +# """Full regularization matrix W""" +# print 'wtf why are we using W' +# if getattr(self, '_W', None) is None: +# wlist = (self.Wsmall, self.Wx) +# if self.regmesh.dim > 1: +# wlist += (self.Wy,) +# if self.regmesh.dim > 2: +# wlist += (self.Wz,) +# self._W = sp.vstack(wlist) +# return self._W + + + @Utils.timeIt + def _evalSmall(self, m): + r = self.Wsmall * ( self.mapping * (m - self.mref) ) + return 0.5 * r.dot(r) + + @Utils.timeIt + def _evalSmallDeriv(self, m): + r = self.Wsmall * ( self.mapping * (m - self.mref) ) + return r.T * ( self.Wsmall * self.mapping.deriv(m - self.mref) ) + + @Utils.timeIt + def _evalSmall2Deriv(self, m, v = None): + rDeriv = self.Wsmall * ( self.mapping.deriv(m - self.mref) ) + if v is not None: + return rDeriv.T * (rDeriv * v) + return rDeriv.T * rDeriv + + @Utils.timeIt + def _evalSmoothx(self, m): + if self.mrefInSmooth == True: + r = self.Wx * ( self.mapping * (m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wx * ( self.mapping * (m) ) + return 0.5 * r.dot(r) + + @Utils.timeIt + def _evalSmoothy(self, m): + if self.mrefInSmooth == True: + r = self.Wy * ( self.mapping * (m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wy * ( self.mapping * (m) ) + return 0.5 * r.dot(r) + + @Utils.timeIt + def _evalSmoothz(self, m): + if self.mrefInSmooth == True: + r = self.Wz * ( self.mapping * (m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wz * ( self.mapping * (m) ) + return 0.5 * r.dot(r) + + @Utils.timeIt + def _evalSmooth(self, m): + phiSmooth = self._evalSmoothx(m) + if self.regmesh.dim > 1: + phiSmooth += self._evalSmoothy(m) + if self.regmesh.dim > 2: + phiSmooth += self._evalSmoothz(m) + return phiSmooth + + @Utils.timeIt + def _evalSmoothxDeriv(self, m): + if self.mrefInSmooth == True: + r = self.Wx * ( self.mapping * ( m - self.mref ) ) + return r.T * ( self.Wx * self.mapping.deriv(m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wx * ( self.mapping * m ) + return r.T * ( self.Wx * self.mapping.deriv(m) ) + + @Utils.timeIt + def _evalSmoothx2Deriv(self, m, v=None): + if self.mrefInSmooth == True: + rDeriv = self.Wx * ( self.mapping.deriv( m - self.mref ) ) + elif self.mrefInSmooth == False: + rDeriv = self.Wx * ( self.mapping.deriv(m) ) + + if v is not None: + return rDeriv.T * ( rDeriv * v ) + return rDeriv.T * rDeriv + + @Utils.timeIt + def _evalSmoothyDeriv(self, m): + if self.mrefInSmooth == True: + r = self.Wy * ( self.mapping * ( m - self.mref ) ) + return r.T * ( self.Wy * self.mapping.deriv(m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wy * ( self.mapping * m ) + return r.T * ( self.Wy * self.mapping.deriv(m) ) + + @Utils.timeIt + def _evalSmoothy2Deriv(self, m, v=None): + if self.mrefInSmooth == True: + rDeriv = self.Wy * ( self.mapping.deriv( m - self.mref ) ) + elif self.mrefInSmooth == False: + rDeriv = self.Wy * ( self.mapping.deriv(m) ) + + if v is not None: + return rDeriv.T * ( rDeriv * v ) + return rDeriv.T * rDeriv + + @Utils.timeIt + def _evalSmoothzDeriv(self, m): + if self.mrefInSmooth == True: + r = self.Wz * ( self.mapping * ( m - self.mref ) ) + return r.T * ( self.Wz * self.mapping.deriv(m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wz * ( self.mapping * m ) + return r.T * ( self.Wz * self.mapping.deriv(m) ) + + @Utils.timeIt + def _evalSmoothz2Deriv(self, m, v=None): + if self.mrefInSmooth == True: + rDeriv = self.Wz * ( self.mapping.deriv( m - self.mref ) ) + elif self.mrefInSmooth == False: + rDeriv = self.Wz * ( self.mapping.deriv(m) ) + + if v is not None: + return rDeriv.T * ( rDeriv * v ) + return rDeriv.T * rDeriv + + @Utils.timeIt + def _evalSmoothDeriv(self, m): + deriv = self._evalSmoothxDeriv(m) + if self.regmesh.dim > 1: + deriv += self._evalSmoothyDeriv(m) + if self.regmesh.dim > 2: + deriv += self._evalSmoothzDeriv(m) + return deriv + + @Utils.timeIt + def _evalSmooth2Deriv(self, m, v=None): + deriv = self._evalSmoothx2Deriv(m, v) + if self.regmesh.dim > 1: + deriv += self._evalSmoothy2Deriv(m, v) + if self.regmesh.dim > 2: + deriv += self._evalSmoothz2Deriv(m, v) + return deriv + + + @Utils.timeIt + def eval(self, m): + return self._evalSmall(m) + self._evalSmooth(m) + + @Utils.timeIt + def evalDeriv(self, m): + """ + The regularization is: + + .. math:: + + R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})} + + So the derivative is straight forward: + + .. math:: + + R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} + + """ + return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) + + @Utils.timeIt + def eval2Deriv(self, m, v=None): + return self._evalSmall2Deriv(m, v) + self._evalSmooth2Deriv(m, v) + + + +class Tikhonov(Simple): """ L2 Tikhonov regularization with both smallness and smoothness (first order derivative) contributions. @@ -417,8 +650,8 @@ class Tikhonov(BaseRegularization): Note if the key word argument `mrefInSmooth` is False, then mref is not included in the smoothness contribution. - :param Mesh mesh: SimPEG mesh - :param Maps mapping: regularization mapping, takes the model from model space to the thing you want to regularize + :param BaseMesh mesh: SimPEG mesh + :param IdentityMap mapping: regularization mapping, takes the model from model space to the thing you want to regularize :param numpy.ndarray indActive: active cell indices for reducing the size of differential operators in the definition of a regularization mesh :param bool mrefInSmooth: (default = False) put mref in the smoothness component? :param float alpha_s: (default 1e-6) smallness weight @@ -438,7 +671,7 @@ class Tikhonov(BaseRegularization): alpha_yy = Utils.dependentProperty('_alpha_yy', 0.0, ['_W', '_Wyy'], "Weight for the second derivative in the y direction") alpha_zz = Utils.dependentProperty('_alpha_zz', 0.0, ['_W', '_Wzz'], "Weight for the second derivative in the z direction") - def __init__(self, mesh, mapping=None, indActive = None, **kwargs): + def __init__(self, mesh, mapping=None, indActive=None, **kwargs): BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) @property @@ -493,56 +726,131 @@ class Tikhonov(BaseRegularization): self._Wzz = Utils.sdiag((self.regmesh.vol*self.alpha_zz)**0.5)*self.regmesh.faceDiffz*self.regmesh.cellDiffz return self._Wzz + @property - def Wsmooth(self): + def Wsmooth2(self): """Full smoothness regularization matrix W""" if getattr(self, '_Wsmooth', None) is None: - wlist = (self.Wx, self.Wxx) + wlist = (self.Wxx) if self.regmesh.dim > 1: - wlist += (self.Wy, self.Wyy) + wlist += (self.Wyy) if self.regmesh.dim > 2: - wlist += (self.Wz, self.Wzz) + wlist += (self.Wzz) self._Wsmooth = sp.vstack(wlist) return self._Wsmooth - @property - def W(self): - """Full regularization matrix W""" - if getattr(self, '_W', None) is None: - wlist = (self.Wsmall, self.Wsmooth) - self._W = sp.vstack(wlist) - return self._W - @Utils.timeIt - def _evalSmall(self, m): - r = self.Wsmall * ( self.mapping * (m - self.mref) ) - return 0.5 * r.dot(r) - - @Utils.timeIt - def _evalSmooth(self, m): + def _evalSmoothxx(self, m): if self.mrefInSmooth == True: - r = self.Wsmooth * ( self.mapping * (m - self.mref) ) + r = self.Wxx * ( self.mapping * (m - self.mref) ) elif self.mrefInSmooth == False: - r = self.Wsmooth * ( self.mapping * (m) ) + r = self.Wxx * ( self.mapping * (m) ) return 0.5 * r.dot(r) + @Utils.timeIt + def _evalSmoothyy(self, m): + if self.mrefInSmooth == True: + r = self.Wyy * ( self.mapping * (m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wyy * ( self.mapping * (m) ) + return 0.5 * r.dot(r) + + @Utils.timeIt + def _evalSmoothzz(self, m): + if self.mrefInSmooth == True: + r = self.Wzz * ( self.mapping * (m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wzz * ( self.mapping * (m) ) + return 0.5 * r.dot(r) + + @Utils.timeIt + def _evalSmooth2(self, m): + phiSmooth2 = self._evalSmoothxx(m) + if self.regmesh.dim > 1: + phiSmooth2 += self._evalSmoothyy(m) + if self.regmesh.dim > 2: + phiSmooth2 += self._evalSmoothzz(m) + return phiSmooth2 + + @Utils.timeIt + def _evalSmoothxxDeriv(self, m): + if self.mrefInSmooth == True: + r = self.Wxx * ( self.mapping * ( m - self.mref ) ) + return r.T * ( self.Wxx * self.mapping.deriv(m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wxx * ( self.mapping * m ) + return r.T * ( self.Wxx * self.mapping.deriv(m) ) + + @Utils.timeIt + def _evalSmoothyyDeriv(self, m): + if self.mrefInSmooth == True: + r = self.Wyy * ( self.mapping * ( m - self.mref ) ) + return r.T * ( self.Wyy * self.mapping.deriv(m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wyy * ( self.mapping * m ) + return r.T * ( self.Wyy * self.mapping.deriv(m) ) + + @Utils.timeIt + def _evalSmoothzzDeriv(self, m): + if self.mrefInSmooth == True: + r = self.Wzz * ( self.mapping * ( m - self.mref ) ) + return r.T * ( self.Wzz * self.mapping.deriv(m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wzz * ( self.mapping * m ) + return r.T * ( self.Wzz * self.mapping.deriv(m) ) + + @Utils.timeIt + def _evalSmoothxx2Deriv(self, m, v=None): + if self.mrefInSmooth == True: + rDeriv = self.Wxx * ( self.mapping.deriv( m - self.mref ) ) + elif self.mrefInSmooth == False: + rDeriv = self.Wxx * self.mapping.deriv(m) + if v is not None: + return rDeriv.T * (rDeriv * v) + return rDeriv.T * rDeriv + + @Utils.timeIt + def _evalSmoothyy2Deriv(self, m, v=None): + if self.mrefInSmooth == True: + rDeriv = self.Wyy * ( self.mapping.deriv( m - self.mref ) ) + elif self.mrefInSmooth == False: + rDeriv = self.Wyy * self.mapping.deriv(m) + if v is not None: + return rDeriv.T * (rDeriv * v) + return rDeriv.T * rDeriv + + @Utils.timeIt + def _evalSmoothzz2Deriv(self, m, v=None): + if self.mrefInSmooth == True: + rDeriv = self.Wzz * ( self.mapping.deriv( m - self.mref ) ) + elif self.mrefInSmooth == False: + rDeriv = self.Wzz * self.mapping.deriv(m) + if v is not None: + return rDeriv.T * (rDeriv * v) + return rDeriv.T * rDeriv + + @Utils.timeIt + def _evalSmoothDeriv2(self, m): + deriv = self._evalSmoothxxDeriv(m) + if self.regmesh.dim > 1: + deriv += self._evalSmoothyyDeriv(m) + if self.regmesh.dim > 2: + deriv += self._evalSmoothzzDeriv(m) + return deriv + + @Utils.timeIt + def _evalSmooth2Deriv2(self, m, v=None): + deriv = self._evalSmoothxx2Deriv(m, v) + if self.regmesh.dim > 1: + deriv += self._evalSmoothyy2Deriv(m, v) + if self.regmesh.dim > 2: + deriv += self._evalSmoothzz2Deriv(m, v) + return deriv + + @Utils.timeIt def eval(self, m): - return self._evalSmall(m) + self._evalSmooth(m) - - @Utils.timeIt - def _evalSmallDeriv(self,m): - r = self.Wsmall * ( self.mapping * (m - self.mref) ) - return r.T * ( self.Wsmall * self.mapping.deriv(m - self.mref) ) - - @Utils.timeIt - def _evalSmoothDeriv(self,m): - if self.mrefInSmooth == True: - r = self.Wsmooth * ( self.mapping * ( m - self.mref ) ) - return r.T * ( self.Wsmooth * self.mapping.deriv(m - self.mref) ) - elif self.mrefInSmooth == False: - r = self.Wsmooth * ( self.mapping * m ) - return r.T * ( self.Wsmooth * self.mapping.deriv(m) ) + return self._evalSmall(m) + self._evalSmooth(m) + self._evalSmooth2(m) @Utils.timeIt def evalDeriv(self, m): @@ -560,184 +868,134 @@ class Tikhonov(BaseRegularization): R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} """ - return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) + return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) + self._evalSmoothDeriv2(m) + + def eval2Deriv(self, m, v=None): + """ + The regularization is: + + .. math:: + + R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})} + + So the derivative is straight forward: + + .. math:: + + R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} + + """ + return self._evalSmall2Deriv(m, v) + self._evalSmooth2Deriv(m, v) + self._evalSmooth2Deriv2(m, v) -class Simple(Tikhonov): + +class Sparse(Simple): """ - Simple regularization that does not include length scales in the derivatives. + The regularization is: + + .. math:: + + R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top R^\\top R W(m-m_\\text{ref})} + + where the IRLS weight + + .. math:: + + R = \eta TO FINISH LATER!!! + + So the derivative is straight forward: + + .. math:: + + R(m) = \mathbf{W^\\top R^\\top R W (m-m_\\text{ref})} + + The IRLS weights are recomputed after each beta solves. + It is strongly recommended to do a few Gauss-Newton iterations + before updating. """ - - mrefInSmooth = False #: SMOOTH and SMOOTH_MOD_DIF options - alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Wsmall'], "Smallness weight") - alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") - alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") - alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") - wght = 1. + + # set default values + eps_p = 1e-1 # Threshold value for the model norm + eps_q = 1e-1 # Threshold value for the model gradient norm + curModel = None # Requires model to compute the weights + l2model = None + gamma = 1. # Model norm scaling to smooth out convergence + norms = [0., 2., 2., 2.] # Values for norm on (m, dmdx, dmdy, dmdz) + cell_weights = 1. # Consider overwriting with sensitivity weights def __init__(self, mesh, mapping=None, indActive=None, **kwargs): - BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) + Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) - if isinstance(self.wght,float): - self.wght = np.ones(self.regmesh.nC) * self.wght + if isinstance(self.cell_weights,float): + self.cell_weights = np.ones(self.regmesh.nC) * self.cell_weights @property def Wsmall(self): """Regularization matrix Wsmall""" if getattr(self,'_Wsmall', None) is None: - self._Wsmall = Utils.sdiag((self.regmesh.vol*self.alpha_s*self.wght)**0.5) + if getattr(self, 'curModel', None) is None: + self.Rs = Utils.speye(self.regmesh.nC) + + else: + f_m = self.mapping * (self.curModel - self.reg.mref) + self.rs = self.R(f_m , self.eps_p, self.norms[0]) + self.Rs = Utils.sdiag( self.rs ) + + self._Wsmall = Utils.sdiag((self.alpha_s*self.gamma*self.cell_weights)**0.5)*self.Rs + return self._Wsmall @property def Wx(self): """Regularization matrix Wx""" - if getattr(self, '_Wx', None) is None: - self._Wx = Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.regmesh.cellDiffxStencil + if getattr(self,'_Wx', None) is None: + if getattr(self, 'curModel', None) is None: + self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0]) + + else: + f_m = self.regmesh.cellDiffxStencil * (self.mapping * self.curModel) + self.rx = self.R( f_m , self.eps_q, self.norms[1]) + self.Rx = Utils.sdiag( self.rx ) + + self._Wx = Utils.sdiag(( self.alpha_x*self.gamma*(self.regmesh.aveCC2Fx*self.cell_weights))**0.5)*self.Rx*self.regmesh.cellDiffxStencil + return self._Wx @property def Wy(self): """Regularization matrix Wy""" - if getattr(self, '_Wy', None) is None: - self._Wy = Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol * self.alpha_y*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.regmesh.cellDiffyStencil + if getattr(self,'_Wy', None) is None: + if getattr(self, 'curModel', None) is None: + self.Ry = Utils.speye(self.regmesh.cellDiffyStencil.shape[0]) + + else: + f_m = self.regmesh.cellDiffyStencil * (self.mapping * self.curModel) + self.ry = self.R( f_m , self.eps_q, self.norms[2]) + self.Ry = Utils.sdiag( self.ry ) + + self._Wy = Utils.sdiag((self.alpha_y*self.gamma*(self.regmesh.aveCC2Fy*self.cell_weights))**0.5)*self.Ry*self.regmesh.cellDiffyStencil + return self._Wy @property def Wz(self): """Regularization matrix Wz""" - if getattr(self, '_Wz', None) is None: - self._Wz = Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.regmesh.cellDiffzStencil + if getattr(self,'_Wz', None) is None: + if getattr(self, 'curModel', None) is None: + self.Rz = Utils.speye(self.regmesh.cellDiffzStencil.shape[0]) + + else: + f_m = self.regmesh.cellDiffzStencil * (self.mapping * self.curModel) + self.rz = self.R( f_m , self.eps_q, self.norms[3]) + self.Rz = Utils.sdiag( self.rz ) + + self._Wz = Utils.sdiag((self.alpha_z*self.gamma*(self.regmesh.aveCC2Fz*self.cell_weights))**0.5)*self.Rz*self.regmesh.cellDiffzStencil + return self._Wz - @property - def Wsmooth(self): - """Full smoothness regularization matrix W""" - if getattr(self, '_Wsmooth', None) is None: - wlist = (self.Wx,) - if self.regmesh.dim > 1: - wlist += (self.Wy,) - if self.regmesh.dim > 2: - wlist += (self.Wz,) - self._Wsmooth = sp.vstack(wlist) - return self._Wsmooth - - @property - def W(self): - """Full regularization matrix W""" - if getattr(self, '_W', None) is None: - wlist = (self.Wsmall, self.Wsmooth) - self._W = sp.vstack(wlist) - return self._W - - @Utils.timeIt - def _evalSmall(self, m): - r = self.Wsmall * ( self.mapping * (m - self.mref) ) - return 0.5 * r.dot(r) - - @Utils.timeIt - def _evalSmooth(self, m): - if self.mrefInSmooth == True: - r = self.Wsmooth * ( self.mapping * (m - self.mref) ) - elif self.mrefInSmooth == False: - r = self.Wsmooth * ( self.mapping * m) - return 0.5 * r.dot(r) - - -class Sparse(Simple): - - # set default values - eps_p = 1e-1 - eps_q = 1e-1 - curModel = None # use a model to compute the weights - gamma = 1. - norms = [0., 2., 2., 2.] - wght = 1. - - def __init__(self, mesh, mapping=None, indActive=None, **kwargs): - Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) - - if isinstance(self.wght,float): - self.wght = np.ones(self.regmesh.nC) * self.wght - - @property - def Wsmall(self): - """Regularization matrix Wsmall""" - if getattr(self, 'curModel', None) is None: - self.Rs = Utils.speye(self.regmesh.nC) - - else: - f_m = self.curModel - self.reg.mref - self.rs = self.R(f_m , self.eps_p, self.norms[0]) - #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) - self.Rs = Utils.sdiag( self.rs ) - - return Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma*self.wght)**0.5)*self.Rs - - - @property - def Wx(self): - """Regularization matrix Wx""" - - if getattr(self, 'curModel', None) is None: - self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0]) - - else: - f_m = self.regmesh.cellDiffxStencil * self.curModel - self.rx = self.R( f_m , self.eps_q, self.norms[1]) - self.Rx = Utils.sdiag( self.rx ) - - return Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.Rx*self.regmesh.cellDiffxStencil - - @property - def Wy(self): - """Regularization matrix Wy""" - - if getattr(self, 'curModel', None) is None: - self.Ry = Utils.speye(self.regmesh.cellDiffyStencil.shape[0]) - - else: - f_m = self.regmesh.cellDiffyStencil * self.curModel - self.ry = self.R( f_m , self.eps_q, self.norms[2]) - self.Ry = Utils.sdiag( self.ry ) - - return Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.Ry*self.regmesh.cellDiffyStencil - - @property - def Wz(self): - """Regularization matrix Wz""" - - if getattr(self, 'curModel', None) is None: - self.Rz = Utils.speye(self.regmesh.cellDiffzStencil.shape[0]) - - else: - f_m = self.regmesh.cellDiffzStencil * self.curModel - self.rz = self.R( f_m , self.eps_q, self.norms[3]) - self.Rz = Utils.sdiag( self.rz ) - - return Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.Rz*self.regmesh.cellDiffzStencil - - @property - def Wsmooth(self): - """Full smoothness regularization matrix W""" - #if getattr(self, '_Wsmooth', None) is None: - wlist = (self.Wx,) - if self.regmesh.dim > 1: - wlist += (self.Wy,) - if self.regmesh.dim > 2: - wlist += (self.Wz,) - #self._Wsmooth = sp.vstack(wlist) - return sp.vstack(wlist) - - @property - def W(self): - """Full regularization matrix W""" - if getattr(self, '_W', None) is None: - wlist = (self.Wsmall, self.Wsmooth) - self._W = sp.vstack(wlist) - return self._W - def R(self, f_m , eps, exponent): + # Eta scaling is important for mix-norms...do not mess with it eta = (eps**(1.-exponent/2.))**0.5 r = eta / (f_m**2.+ eps**2.)**((1.-exponent/2.)/2.) diff --git a/SimPEG/Survey.py b/SimPEG/Survey.py index fbc88276..65c46972 100644 --- a/SimPEG/Survey.py +++ b/SimPEG/Survey.py @@ -311,7 +311,6 @@ class BaseSurvey(object): if f is None: f = self.prob.fields(m) return Utils.mkvc(self.eval(f)) - @Utils.count def eval(self, f): """eval(f) @@ -322,7 +321,7 @@ class BaseSurvey(object): d_\\text{pred} = \mathbf{P} f(m) """ - raise NotImplemented('eval is not yet implemented.') + raise NotImplementedError('eval is not yet implemented.') @Utils.count def evalDeriv(self, f): @@ -334,7 +333,7 @@ class BaseSurvey(object): \\frac{\partial d_\\text{pred}}{\partial u} = \mathbf{P} """ - raise NotImplemented('eval is not yet implemented.') + raise NotImplementedError('eval is not yet implemented.') @Utils.count def residual(self, m, f=None): diff --git a/SimPEG/Tests.py b/SimPEG/Tests.py index 804ca6b8..ea7a74e1 100644 --- a/SimPEG/Tests.py +++ b/SimPEG/Tests.py @@ -237,7 +237,7 @@ def checkDerivative(fctn, x0, num=7, plotIt=True, dx=None, expectedOrder=2, tole Compares error decay of 0th and 1st order Taylor approximation at point x0 for a randomized search direction. - :param lambda fctn: function handle + :param callable fctn: function handle :param numpy.array x0: point at which to check derivative :param int num: number of times to reduce step length, h :param bool plotIt: if you would like to plot diff --git a/SimPEG/Utils/ModelBuilder.py b/SimPEG/Utils/ModelBuilder.py index 1b868fe5..1f4aa47f 100644 --- a/SimPEG/Utils/ModelBuilder.py +++ b/SimPEG/Utils/ModelBuilder.py @@ -7,11 +7,11 @@ def addBlock(gridCC, modelCC, p0, p1, blockProp): """ Add a block to an exsisting cell centered model, modelCC - :param numpy.array, gridCC: mesh.gridCC is the cell centered grid - :param numpy.array, modelCC: cell centered model - :param numpy.array, p0: bottom, southwest corner of block - :param numpy.array, p1: top, northeast corner of block - :blockProp float, blockProp: property to assign to the model + :param numpy.array gridCC: mesh.gridCC is the cell centered grid + :param numpy.array modelCC: cell centered model + :param numpy.array p0: bottom, southwest corner of block + :param numpy.array p1: top, northeast corner of block + :blockProp float blockProp: property to assign to the model :return numpy.array, modelBlock: model with block """ @@ -147,7 +147,7 @@ def getIndicesSphere(center,radius,ccMesh): if dimMesh == 1: # Define the reference points - + ind = np.abs(center[0] - ccMesh[:,0]) < radius elif dimMesh == 2: @@ -222,14 +222,14 @@ def layeredModel(ccMesh, layerTops, layerValues): :param numpy.array ccMesh: cell-centered mesh :param numpy.array layerTops: z-locations of the tops of each layer - :param numpy.array layerValue: values of the property to assign for each layer (starting at the top) + :param numpy.array layerValue: values of the property to assign for each layer (starting at the top) :rtype: numpy.array - :return: M, layered model on the mesh + :return: M, layered model on the mesh """ descending = np.linalg.norm(sorted(layerTops, reverse=True) - layerTops) < 1e-20 - # TODO: put an error check to make sure that there is an ordering... needs to work with inf elts + # TODO: put an error check to make sure that there is an ordering... needs to work with inf elts # assert ascending or descending, "Layers must be listed in either ascending or descending order" # start from bottom up @@ -253,10 +253,10 @@ def layeredModel(ccMesh, layerTops, layerValues): model = np.zeros(ccMesh.shape[0]) for i, top in enumerate(layerTops): - zind = z <= top + zind = z <= top model[zind] = layerValues[i] - return model + return model @@ -265,9 +265,9 @@ def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=None): Create a random model by convolving a kernel with a uniformly distributed model. - :param int,tuple shape: shape of the model. + :param tuple shape: shape of the model. :param int seed: pick which model to produce, prints the seed if you don't choose. - :param numpy.ndarray,list anisotropy: this is the (3 x n) blurring kernel that is used. + :param numpy.ndarray anisotropy: this is the (3 x n) blurring kernel that is used. :param int its: number of smoothing iterations :param list bounds: bounds on the model, len(list) == 2 :rtype: numpy.ndarray diff --git a/SimPEG/Utils/SolverUtils.py b/SimPEG/Utils/SolverUtils.py index 47c899d3..28a1159d 100644 --- a/SimPEG/Utils/SolverUtils.py +++ b/SimPEG/Utils/SolverUtils.py @@ -13,7 +13,7 @@ def _checkAccuracy(A, b, X, accuracyTol): warnings.warn(msg, RuntimeWarning) -def SolverWrapD(fun, factorize=True, checkAccuracy=True, accuracyTol=1e-6): +def SolverWrapD(fun, factorize=True, checkAccuracy=True, accuracyTol=1e-6, name=None): """ Wraps a direct Solver. @@ -72,11 +72,11 @@ def SolverWrapD(fun, factorize=True, checkAccuracy=True, accuracyTol=1e-6): if factorize and hasattr(self.solver, 'clean'): return self.solver.clean() - return type(fun.__name__+'_Wrapped', (object,), {"__init__": __init__, "clean": clean, "__mul__": __mul__}) + return type(name if name is not None else fun.__name__, (object,), {"__init__": __init__, "clean": clean, "__mul__": __mul__}) -def SolverWrapI(fun, checkAccuracy=True, accuracyTol=1e-5): +def SolverWrapI(fun, checkAccuracy=True, accuracyTol=1e-5, name=None): """ Wraps an iterative Solver. @@ -128,13 +128,13 @@ def SolverWrapI(fun, checkAccuracy=True, accuracyTol=1e-5): def clean(self): pass - return type(fun.__name__+'_Wrapped', (object,), {"__init__": __init__, "clean": clean, "__mul__": __mul__}) + return type(name if name is not None else fun.__name__, (object,), {"__init__": __init__, "clean": clean, "__mul__": __mul__}) from scipy.sparse import linalg -Solver = SolverWrapD(linalg.spsolve, factorize=False) -SolverLU = SolverWrapD(linalg.splu, factorize=True) -SolverCG = SolverWrapI(linalg.cg) +Solver = SolverWrapD(linalg.spsolve, factorize=False, name="Solver") +SolverLU = SolverWrapD(linalg.splu, factorize=True, name="SolverLU") +SolverCG = SolverWrapI(linalg.cg, name="SolverCG") class SolverDiag(object): diff --git a/SimPEG/Utils/interputils.py b/SimPEG/Utils/interputils.py index 17b9b469..16c7bf5e 100644 --- a/SimPEG/Utils/interputils.py +++ b/SimPEG/Utils/interputils.py @@ -25,7 +25,7 @@ def interpmat(locs, x, y=None, z=None): :param numpy.ndarray x: Tensor vector of 1st dimension of grid. :param numpy.ndarray y: Tensor vector of 2nd dimension of grid. None by default. :param numpy.ndarray z: Tensor vector of 3rd dimension of grid. None by default. - :rtype: scipy.sparse.csr.csr_matrix + :rtype: scipy.sparse.csr_matrix :return: Interpolation matrix .. plot:: diff --git a/SimPEG/Utils/matutils.py b/SimPEG/Utils/matutils.py index 3a6030fa..73f414b3 100644 --- a/SimPEG/Utils/matutils.py +++ b/SimPEG/Utils/matutils.py @@ -27,7 +27,7 @@ def mkvc(x, numDims=1): if isinstance(x, Zero): return x - + assert isinstance(x, np.ndarray), "Vector must be a numpy array" if numDims == 1: @@ -355,9 +355,9 @@ def diagEst(matFun, n, k=None, approach='Probing'): 2. Ones : random +/- 1 entries 3. Random : random vectors - :param lambda (numpy.array) matFun: matrix to estimate the diagonal of - :param int64 n: size of the vector that should be used to compute matFun(v) - :param int64 k: number of vectors to be used to estimate the diagonal + :param callable matFun: takes a (numpy.array) and multiplies it by a matrix to estimate the diagonal + :param int n: size of the vector that should be used to compute matFun(v) + :param int k: number of vectors to be used to estimate the diagonal :param str approach: approach to be used for getting vectors :rtype: numpy.array :return: est_diag(A) @@ -422,9 +422,9 @@ class Zero(object): def __ge__(self, v):return 0 >= v def __gt__(self, v):return 0 > v - @property + @property def transpose(self): return Zero() - + @property def T(self): return Zero() diff --git a/SimPEG/Utils/meshutils.py b/SimPEG/Utils/meshutils.py index eb5d13a1..c7ec1efd 100644 --- a/SimPEG/Utils/meshutils.py +++ b/SimPEG/Utils/meshutils.py @@ -83,7 +83,7 @@ def closestPoints(mesh, pts, gridLoc='CC'): """ Move a list of points to the closest points on a grid. - :param simpeg.Mesh.BaseMesh mesh: The mesh + :param BaseMesh mesh: The mesh :param numpy.ndarray pts: Points to move :param string gridLoc: ['CC', 'N', 'Fx', 'Fy', 'Fz', 'Ex', 'Ex', 'Ey', 'Ez'] :rtype: numpy.ndarray @@ -104,16 +104,20 @@ def closestPoints(mesh, pts, gridLoc='CC'): def ExtractCoreMesh(xyzlim, mesh, meshType='tensor'): """ - Extracts Core Mesh from Global mesh - xyzlim: 2D array [ndim x 2] - mesh: SimPEG mesh - This function ouputs: - - actind: corresponding boolean index from global to core - - meshcore: core SimPEG mesh - Warning: 1D and 2D has not been tested + Extracts Core Mesh from Global mesh + + :param numpy.ndarray xyzlim: 2D array [ndim x 2] + :param BaseMesh mesh: The mesh + + This function ouputs:: + + - actind: corresponding boolean index from global to core + - meshcore: core SimPEG mesh + + Warning: 1D and 2D has not been tested """ from SimPEG import Mesh - if mesh.dim ==1: + if mesh.dim == 1: xyzlim = xyzlim.flatten() xmin, xmax = xyzlim[0], xyzlim[1] @@ -125,11 +129,11 @@ def ExtractCoreMesh(xyzlim, mesh, meshType='tensor'): x0 = [xc[0]-hx[0]*0.5, yc[0]-hy[0]*0.5] - meshCore = Mesh.TensorMesh([hx, hy] ,x0=x0) + meshCore = Mesh.TensorMesh([hx, hy], x0=x0) actind = (mesh.gridCC[:,0]>xmin) & (mesh.gridCC[:,0]xmin) & (mesh.gridCC[:,0]ymin) & (mesh.gridCC[:,1]xmin) & (mesh.gridCC[:,0]ymin) & (mesh.gridCC[:,1] + + + + + +{% endblock %} diff --git a/docs/api_FiniteVolume.rst b/docs/api_FiniteVolume.rst deleted file mode 100644 index 40e9b879..00000000 --- a/docs/api_FiniteVolume.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. _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_MeshCode.rst b/docs/api_MeshCode.rst deleted file mode 100644 index 2d7cab9f..00000000 --- a/docs/api_MeshCode.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _api_MeshCode: - -Tensor Mesh -=========== - -.. automodule:: SimPEG.Mesh.TensorMesh - :show-inheritance: - :members: - :undoc-members: - - -Cylindrical Mesh -================ - -.. automodule:: SimPEG.Mesh.CylMesh - :show-inheritance: - :members: - :undoc-members: - - -Tree Mesh -========= - -.. autoclass:: SimPEG.Mesh.TreeMesh.TreeMesh - :show-inheritance: - :members: - :undoc-members: - - -Curvilinear Mesh -================ - -.. automodule:: SimPEG.Mesh.CurvilinearMesh - :show-inheritance: - :members: - :undoc-members: diff --git a/docs/app.yaml b/docs/app.yaml new file mode 100644 index 00000000..f37fb743 --- /dev/null +++ b/docs/app.yaml @@ -0,0 +1,95 @@ +# application: simpegdocs +# version: 1 +runtime: python27 +api_version: 1 +threadsafe: yes + +handlers: + +# favicon +- url: /images/logo-block\.ico + static_files: /images/logo-block.ico + upload: /images/logo-block\.ico + +# all css +- url: /(.*\.css) + mime_type: text/css + static_files: _build/html/\1 + upload: _build/html/(.*\.css) + +# webfonts +- url: /(.*\.(eot|svg|ttf|woff|woff2|otf)) + static_files: _build/html/\1 + upload: _build/html/(.*\.(eot|svg|ttf|woff|woff2|otf)) + +# javascript +- url: /(.*\.js) + mime_type: text/javascript + static_files: _build/html/\1 + upload: _build/html/(.*\.js) + +# plain text source +- url: /(.*\.txt) + mime_type: text/plain + static_files: _build/html/\1 + upload: _build/html/(.*\.txt) + +# images +- url: /_images/(.*\.(gif|png|jpg|ico)) + static_files: _build/html/_images/\1 + upload: _build/html/_images/(.*\.(gif|png|jpg|ico)) + +# redirect en/latest traffic +- url: /en/latest/(.*\.html) + script: simpegdocs.app + +# raw html +- url: /(.*\.html) + mime_type: text/html + static_files: _build/html/\1 + upload: _build/html/(.*\.html) + +# serve index files +- url: /(.+)/ + static_files: _build/html/\1/index.html + upload: _build/html/(.+)/index.html + +- url: /(.+) + static_files: _build/html/\1/index.html + upload: _build/html/(.+)/index.html + +- url: / + static_files: _build/html/index.html + upload: _build/html/index.html + +- url: .* + script: simpegdocs.app + +# Recommended file skipping declaration from the GAE tutorials +skip_files: + - ^(.*/)?app\.yaml + - ^(.*/)?app\.yml + - ^(.*/)?#.*# + - ^(.*/)?.*~ + - ^(.*/)?.*\.py[co] + - ^(.*/)?.*/RCS/.* + - ^(.*/)?\..* + - ^(.*/)?tests$ + - ^(.*/)?test$ + - ^test/(.*/)? + - ^COPYING.LESSER + - ^README\..* + - \.gitignore + - ^\.git/.* + - \.*\.lint$ + - ^(.*/)?.*\.doctree$ + +libraries: +- name: webapp2 + version: "2.5.2" +- name: PIL + version: "1.1.7" +- name: numpy + version: "latest" +- name: jinja2 + version: "latest" diff --git a/docs/conf.py b/docs/conf.py index 45407435..143ea545 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -28,7 +28,7 @@ sys.path.append('../') # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.todo', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', 'sphinx.ext.autodoc', 'matplotlib.sphinxext.plot_directive'] +extensions = ['sphinx.ext.todo', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'matplotlib.sphinxext.plot_directive'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -44,16 +44,16 @@ master_doc = 'index' # General information about the project. project = u'SimPEG' -copyright = u'2013, SimPEG Developers' +copyright = u'2013 - 2016, SimPEG Developers' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '0.1.10' +version = '0.1.11' # The full version, including alpha/beta/rc tags. -release = '0.1.10' +release = '0.1.11' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -124,12 +124,12 @@ except Exception, e: # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +html_favicon = './images/logo-block.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. @@ -229,6 +229,12 @@ man_pages = [ # If true, show URL addresses after external links. #man_show_urls = False +# Intersphinx +intersphinx_mapping = {'python': ('http://docs.python.org/2', None), + 'numpy': ('http://docs.scipy.org/doc/numpy/', None), + 'scipy': ('http://docs.scipy.org/doc/scipy/reference/', None), + 'matplotlib': ('http://matplotlib.sourceforge.net/', None)} + # -- Options for Texinfo output ------------------------------------------------ @@ -251,3 +257,36 @@ texinfo_documents = [ #texinfo_show_urls = 'footnote' autodoc_member_order = 'bysource' + +def supress_nonlocal_image_warn(): + import sphinx.environment + sphinx.environment.BuildEnvironment.warn_node = _supress_nonlocal_image_warn + +def _supress_nonlocal_image_warn(self, msg, node): + from docutils.utils import get_source_line + + if not msg.startswith('nonlocal image URI found:'): + self._warnfunc(msg, '%s:%s' % get_source_line(node)) + +supress_nonlocal_image_warn() + + +nitpick_ignore = [ + ('py:class', 'IdentityMap'), + ('py:class', 'BaseSurvey'), + ('py:class', 'BaseSrc'), + ('py:class', 'BaseRx'), + ('py:class', 'Survey'), + ('py:class', 'FieldsFDEM'), + ('py:class', 'Fields3D_e'), + ('py:class', 'Fields3D_b'), + ('py:class', 'Fields3D_j'), + ('py:class', 'Fields3D_h'), + ('py:class', 'SurveyTDEM'), + ('py:class', 'SrcTDEM'), + ('py:class', 'EMPropMap'), + ('py:class', 'Data'), + ('py:class', 'SurveyDC'), + ('py:class', 'BaseMTFields'), + ('py:class', 'SolverLU'), +] diff --git a/docs/api_DataMisfit.rst b/docs/content/api_core/api_DataMisfit.rst similarity index 100% rename from docs/api_DataMisfit.rst rename to docs/content/api_core/api_DataMisfit.rst diff --git a/docs/api_DiffOps.rst b/docs/content/api_core/api_DiffOps.rst similarity index 100% rename from docs/api_DiffOps.rst rename to docs/content/api_core/api_DiffOps.rst diff --git a/docs/api_Examples.rst b/docs/content/api_core/api_Examples.rst similarity index 93% rename from docs/api_Examples.rst rename to docs/content/api_core/api_Examples.rst index 68589fb3..40b34949 100644 --- a/docs/api_Examples.rst +++ b/docs/content/api_core/api_Examples.rst @@ -7,7 +7,7 @@ Examples :maxdepth: 1 :glob: - examples/* + ../examples/* External Notebooks diff --git a/docs/content/api_core/api_FiniteVolume.rst b/docs/content/api_core/api_FiniteVolume.rst new file mode 100644 index 00000000..7952c56a --- /dev/null +++ b/docs/content/api_core/api_FiniteVolume.rst @@ -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 `_). 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/content/api_core/api_ForwardProblem.rst similarity index 68% rename from docs/api_ForwardProblem.rst rename to docs/content/api_core/api_ForwardProblem.rst index 0bf9596f..7d85aab5 100644 --- a/docs/api_ForwardProblem.rst +++ b/docs/content/api_core/api_ForwardProblem.rst @@ -52,13 +52,15 @@ We can take the derivative of the PDE: \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}\\): +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. +This can often be computed given a vector (i.e. \\(J(v)\\)) rather than +stored, as \\(J\\) is a large dense matrix. @@ -67,13 +69,45 @@ The API Problem ------- -.. automodule:: SimPEG.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 ------ -.. automodule:: SimPEG.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: diff --git a/docs/api_InnerProducts.rst b/docs/content/api_core/api_InnerProducts.rst similarity index 74% rename from docs/api_InnerProducts.rst rename to docs/content/api_core/api_InnerProducts.rst index bc9426c6..b1d253b1 100644 --- a/docs/api_InnerProducts.rst +++ b/docs/content/api_core/api_InnerProducts.rst @@ -4,7 +4,10 @@ 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: +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:: @@ -14,12 +17,15 @@ 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. + 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. + +We will start with the formulation of the Direct Current (DC) resistivity +problem in geophysics. .. math:: @@ -28,12 +34,13 @@ We will start with the formulation of the Direct Current (DC) resistivity proble \nabla\cdot \vec{j} = q -In the following discretization, \\\( \\sigma \\\) and \\\( \\phi \\\) -will be discretized on the cell-centers and the flux, \\\(\\vec{j}\\\), +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 \\\(\\vec{f}\\\): +We can define in weak form by integrating with a general face function +:math:`\vec{f}`: .. math:: @@ -61,9 +68,16 @@ We can then discretize for every cell: .. note:: - We have discretized the dot product above, but remember that we do not really have a single vector \\\(\\mathbf{J}\\\), but approximations of \\\(\\vec{j}\\\) on each face of our cell. In 2D that means 2 approximations of \\\(\\mathbf{J}_x\\\) and 2 approximations of \\\(\\mathbf{J}_y\\\). In 3D we also have 2 approximations of \\\(\\mathbf{J}_z\\\). + 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. +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:: @@ -71,14 +85,17 @@ Regardless of how we choose to approximate this dot product, we can represent th -\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 \\\(\\mathbf{J}_c\\\) is the Cartesian \\\(\\mathbf{J}\\\) (on the faces that we choose to use in our approximation) and must be calculated differently depending on the mesh: +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 \\\(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 \\\( \\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: +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:: @@ -107,10 +124,12 @@ By defining the faceInnerProduct (8 combinations of fluxes in 3D, 4 in 2D, 2 in \sum_{i=1}^{2^d} \mathbf{P}_{(i)}^{\top} \Sigma^{-1} \mathbf{P}_{(i)} -Where \\\(d\\\) is the dimension of the mesh. -The \\\( \\mathbf{M}^f \\\) is returned when given the input of \\\( \\Sigma^{-1} \\\). +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 \\( \\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): +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:: @@ -129,7 +148,10 @@ If ``returnP=True`` is requested in any of these methods the projection matrices # 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. +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 @@ -137,7 +159,8 @@ 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: +Depending on the number of columns (either 1, 3, or 6) of mu, the material +property is interpreted as follows: .. math:: @@ -188,13 +211,16 @@ Which is nice and easy to invert if necessary, however, in the fully anisotropic 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 \\\(\\mathbf{M}^f_\\Sigma\\\) and take the derivative when this is multiplied by some vector \\\(\\mathbf{v}\\\): +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 \\\( \\mathbf{Pv} = \\mathbf{y} \\\) and \\\(\\mathbf{y}\\\) will have the form: +Here we will let :math:`\mathbf{Pv} = \mathbf{y}` and :math:`\mathbf{y}` will have the form: .. math:: @@ -233,7 +259,9 @@ Here we will let \\\( \\mathbf{Pv} = \\mathbf{y} \\\) and \\\(\\mathbf{y}\\\) wi \end{matrix} \right] -Now it is easy to take the derivative with respect to any one of the parameters, for example, \\\(\\frac{\\partial}{\\partial\\boldsymbol{\\sigma}_1}\\\) +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) @@ -247,7 +275,8 @@ Now it is easy to take the derivative with respect to any one of the parameters, \end{matrix} \right] -Whereas \\\(\\frac{\\partial}{\\partial\\boldsymbol{\\sigma}_4}\\\), for example, is: +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) @@ -261,11 +290,12 @@ Whereas \\\(\\frac{\\partial}{\\partial\\boldsymbol{\\sigma}_4}\\\), for example \end{matrix} \right] -These are computed for each of the 8 projections, horizontally concatenated, and returned. +These are computed for each of the 8 projections, horizontally concatenated, +and returned. The API ------- -.. automodule:: SimPEG.Mesh.InnerProducts +.. autoclass:: SimPEG.Mesh.InnerProducts.InnerProducts :members: :undoc-members: diff --git a/docs/api_Inversion.rst b/docs/content/api_core/api_Inversion.rst similarity index 74% rename from docs/api_Inversion.rst rename to docs/content/api_core/api_Inversion.rst index 5cac5f0c..a20924cc 100644 --- a/docs/api_Inversion.rst +++ b/docs/content/api_core/api_Inversion.rst @@ -3,7 +3,7 @@ InvProblem ********** -.. automodule:: SimPEG.InvProblem +.. autoclass:: SimPEG.InvProblem.BaseInvProblem :show-inheritance: :members: :undoc-members: @@ -12,7 +12,7 @@ InvProblem Inversion ********* -.. automodule:: SimPEG.Inversion +.. autoclass:: SimPEG.Inversion.BaseInversion :show-inheritance: :members: :undoc-members: diff --git a/docs/api_InversionComponents.rst b/docs/content/api_core/api_InversionComponents.rst similarity index 100% rename from docs/api_InversionComponents.rst rename to docs/content/api_core/api_InversionComponents.rst diff --git a/docs/api_Maps.rst b/docs/content/api_core/api_Maps.rst similarity index 94% rename from docs/api_Maps.rst rename to docs/content/api_core/api_Maps.rst index 0ab32024..a5de8a2f 100644 --- a/docs/api_Maps.rst +++ b/docs/content/api_core/api_Maps.rst @@ -27,7 +27,8 @@ 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 @@ -46,14 +47,15 @@ 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.Vertical1DMap`), +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.Vertical1DMap(M) + 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! @@ -64,7 +66,7 @@ done by the :class:`SimPEG.Maps.ExpMap` described above. from SimPEG import * import matplotlib.pyplot as plt M = Mesh.TensorMesh([7,5]) - v1dMap = Maps.Vertical1DMap(M) + 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! @@ -122,6 +124,8 @@ When these are used in the inverse problem, this is extremely important!! The API ======= +The :code:`IdentityMap` is the base class for all mappings, and it does absolutely nothing. + .. autoclass:: SimPEG.Maps.IdentityMap :members: :undoc-members: @@ -130,7 +134,6 @@ The API Common Maps =========== - Exponential Map --------------- @@ -148,7 +151,7 @@ lives (i.e. it varies logarithmically). Vertical 1D Map --------------- -.. autoclass:: SimPEG.Maps.Vertical1DMap +.. autoclass:: SimPEG.Maps.SurjectVertical1D :members: :undoc-members: @@ -196,8 +199,8 @@ Mesh to Mesh Map :undoc-members: -Some Extras -=========== +Under the Hood +============== Combo Map --------- diff --git a/docs/api_Mesh.rst b/docs/content/api_core/api_Mesh.rst similarity index 99% rename from docs/api_Mesh.rst rename to docs/content/api_core/api_Mesh.rst index ed216b13..93767ee2 100644 --- a/docs/api_Mesh.rst +++ b/docs/content/api_core/api_Mesh.rst @@ -188,6 +188,6 @@ other types of meshes in this SimPEG framework. The API ======= -.. automodule:: SimPEG.Mesh.BaseMesh +.. autoclass:: SimPEG.Mesh.BaseMesh.BaseMesh :members: :undoc-members: diff --git a/docs/content/api_core/api_MeshCode.rst b/docs/content/api_core/api_MeshCode.rst new file mode 100644 index 00000000..39f168a1 --- /dev/null +++ b/docs/content/api_core/api_MeshCode.rst @@ -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: diff --git a/docs/api_Optimization.rst b/docs/content/api_core/api_Optimization.rst similarity index 100% rename from docs/api_Optimization.rst rename to docs/content/api_core/api_Optimization.rst diff --git a/docs/content/api_core/api_PropMaps.rst b/docs/content/api_core/api_PropMaps.rst new file mode 100644 index 00000000..1d0f951d --- /dev/null +++ b/docs/content/api_core/api_PropMaps.rst @@ -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: + diff --git a/docs/api_Regularization.rst b/docs/content/api_core/api_Regularization.rst similarity index 93% rename from docs/api_Regularization.rst rename to docs/content/api_core/api_Regularization.rst index 4ea1a554..b958e98c 100644 --- a/docs/api_Regularization.rst +++ b/docs/content/api_core/api_Regularization.rst @@ -91,10 +91,21 @@ The API :members: :undoc-members: +.. autoclass:: SimPEG.Regularization.Simple + :show-inheritance: + :members: .. autoclass:: SimPEG.Regularization.Tikhonov :show-inheritance: :members: +.. autoclass:: SimPEG.Regularization.Sparse + :show-inheritance: + :members: + +.. autoclass:: SimPEG.Regularization.RegularizationMesh + :show-inheritance: + :members: + diff --git a/docs/api_Solver.rst b/docs/content/api_core/api_Solver.rst similarity index 98% rename from docs/api_Solver.rst rename to docs/content/api_core/api_Solver.rst index d96bd9b2..2d237c46 100644 --- a/docs/api_Solver.rst +++ b/docs/content/api_core/api_Solver.rst @@ -46,6 +46,8 @@ The API ======= .. autofunction:: SimPEG.Utils.SolverUtils.SolverWrapD + :noindex: .. autofunction:: SimPEG.Utils.SolverUtils.SolverWrapI + :noindex: diff --git a/docs/api_Tests.rst b/docs/content/api_core/api_Tests.rst similarity index 100% rename from docs/api_Tests.rst rename to docs/content/api_core/api_Tests.rst diff --git a/docs/api_Utilities.rst b/docs/content/api_core/api_Utilities.rst similarity index 86% rename from docs/api_Utilities.rst rename to docs/content/api_core/api_Utilities.rst index c3a08b30..2f03c54e 100644 --- a/docs/api_Utilities.rst +++ b/docs/content/api_core/api_Utilities.rst @@ -6,5 +6,6 @@ Utilities api_Solver api_Maps + api_PropMaps api_Utils api_Tests diff --git a/docs/api_Utils.rst b/docs/content/api_core/api_Utils.rst similarity index 94% rename from docs/api_Utils.rst rename to docs/content/api_core/api_Utils.rst index 1bf86516..e6f7bb27 100644 --- a/docs/api_Utils.rst +++ b/docs/content/api_core/api_Utils.rst @@ -21,7 +21,7 @@ Solver Utilities :undoc-members: Curv Utilities -============= +============== .. automodule:: SimPEG.Utils.curvutils :members: @@ -51,7 +51,9 @@ Interpolation Utilities Counter Utilities ================= -:: +.. code-block:: python + :linenos: + class MyClass(object): def __init__(self, url): self.counter = Counter() @@ -69,7 +71,9 @@ Counter Utilities for i in range(300): c.MySecondMethod() c.counter.summary() -:: + +.. code-block:: text + :linenos: Counters: MyClass.MyMethod : 100 @@ -77,6 +81,8 @@ Counter Utilities Times: mean sum MyClass.MySecondMethod : 1.70e-06, 5.10e-04, 300x + + The API ------- diff --git a/docs/api_bigPicture.rst b/docs/content/api_core/api_bigPicture.rst similarity index 65% rename from docs/api_bigPicture.rst rename to docs/content/api_core/api_bigPicture.rst index 90266650..0b0f1110 100644 --- a/docs/api_bigPicture.rst +++ b/docs/content/api_core/api_bigPicture.rst @@ -35,7 +35,7 @@ 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 +.. image:: ../../images/InversionWorkflow-PreSimPEG.png :width: 400 px :alt: Components :align: center @@ -46,24 +46,24 @@ 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 +.. 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`) 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 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`) 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. +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 +.. include:: ../../../CITATION.rst Authors ------- -.. include:: ../AUTHORS.rst +.. include:: ../../../AUTHORS.rst License ------- -.. include:: ../LICENSE +.. include:: ../../../LICENSE diff --git a/docs/api_installing.rst b/docs/content/api_core/api_installing.rst similarity index 100% rename from docs/api_installing.rst rename to docs/content/api_core/api_installing.rst diff --git a/docs/api_DC.rst b/docs/content/dc/index.rst similarity index 89% rename from docs/api_DC.rst rename to docs/content/dc/index.rst index f6c98d09..27ec89bd 100644 --- a/docs/api_DC.rst +++ b/docs/content/dc/index.rst @@ -1,5 +1,3 @@ -.. _api_DC: - .. math:: \renewcommand{\div}{\nabla\cdot\,} @@ -38,8 +36,16 @@ \renewcommand {\u} { {\vec u} } \newcommand{\I}{\vec{I}} + +Direct Current Resistivity +************************** + +`SimPEG.DCIP` uses SimPEG as the framework for the forward and inverse +direct current (DC) resistivity and induced polarization (IP) geophysical problems. + + DC resistivity survey -********************* +===================== Electrical resistivity of subsurface materials is measured by causing an electrical current to flow in the earth between one pair of electrodes while the voltage across a second pair of electrodes is measured. The result is an "apparent" resistivity which is a value representing the weighted average resistivity over a volume of the earth. Variations in this measurement are caused by variations in the soil, rock, and pore fluid electrical resistivity. Surveys require contact with the ground, so they can be labour intensive. Results are sometimes interpreted directly, but more commonly, 1D, 2D or 3D models are estimated using inversion procedures (`GPG `_). @@ -55,7 +61,7 @@ As direct current (DC) implies, in DC resistivity survey, we assume steady-state \curl \e = 0 -Then by taking \\(\\curl\\) for the first equation, we have +Then by taking \\(\\div\\) of the first equation, we have .. math:: @@ -137,13 +143,14 @@ Comparing to the analytic function: .. plot:: - import simpegDC as DC - DC.Examples.Verification.run(plotIt=True) + from SimPEG import Examples + Examples.DC_Analytic_Dipole.run(plotIt=True) -API -=== -.. automodule:: simpegDC.BaseDC +API for DC codes +================ + +.. automodule:: SimPEG.DCIP.BaseDC :show-inheritance: :members: :undoc-members: diff --git a/docs/em/api_FDEM.rst b/docs/content/em/api_FDEM.rst similarity index 85% rename from docs/em/api_FDEM.rst rename to docs/content/em/api_FDEM.rst index 778e0b3a..65589c70 100644 --- a/docs/em/api_FDEM.rst +++ b/docs/content/em/api_FDEM.rst @@ -9,17 +9,28 @@ Frequency Domain Electromagnetics ********************************* -Electromagnetic (EM) geophysical methods are used in a variety of applications from resource exploration, including for hydrocarbons and minerals, to environmental applications, such as groundwater monitoring. The primary physical property of interest in EM is electrical conductivity, which describes the ease with which electric current flows through a material. +Electromagnetic (EM) geophysical methods are used in a variety of applications +from resource exploration, including for hydrocarbons and minerals, to +environmental applications, such as groundwater monitoring. The primary +physical property of interest in EM is electrical conductivity, which +describes the ease with which electric current flows through a material. Background ========== -Electromagnetic phenomena are governed by Maxwell's equations. They describe the behavior of EM fields and fluxes. Electromagnetic theory for geophysical applications by Ward and Hohmann (1988) is a highly recommended resource on this topic. +Electromagnetic phenomena are governed by Maxwell's equations. They describe +the behavior of EM fields and fluxes. Electromagnetic theory for geophysical +applications by Ward and Hohmann (1988) is a highly recommended resource on +this topic. Fourier Transform Convention ---------------------------- -In order to examine Maxwell's equations in the frequency domain, we must first define our choice of harmonic time-dependence by choosing a Fourier transform convention. We use the :math:`e^{i \omega t}` convention, so we define our Fourier Transform pair as + +In order to examine Maxwell's equations in the frequency domain, we must first +define our choice of harmonic time-dependence by choosing a Fourier transform +convention. We use the :math:`e^{i \omega t}` convention, so we define our +Fourier Transform pair as .. math :: F(\omega) = \int_{-\infty}^{\infty} f(t) e^{- i \omega t} dt \\ @@ -31,6 +42,7 @@ where :math:`\omega` is angular frequency, :math:`t` is time, :math:`F(\omega)` Maxwell's Equations =================== + In the frequency domain, Maxwell's equations are given by .. math :: @@ -104,19 +116,20 @@ The H-J formulation is in terms of the current density and the magnetic field: Discretizing ------------ + For both formulations, we use a finite volume discretization and discretize fields on cell edges, fluxes on cell faces and physical properties in cell centers. This is particularly important when using symmetry to reduce the dimensionality of a problem (for instance on a 2D CylMesh, there are :math:`r`, :math:`z` faces and :math:`\theta` edges) -.. figure:: ../images/finitevolrealestate.png +.. figure:: ../../images/finitevolrealestate.png :align: center :scale: 60 % For the two formulations, the discretization of the physical properties, fields and fluxes are summarized below. -.. figure:: ../images/ebjhdiscretizations.png +.. figure:: ../../images/ebjhdiscretizations.png :align: center :scale: 60 % @@ -150,7 +163,7 @@ API FDEM Problem ------------ -.. automodule:: SimPEG.EM.FDEM.FDEM +.. automodule:: SimPEG.EM.FDEM.ProblemFDEM :show-inheritance: :members: :undoc-members: @@ -169,6 +182,11 @@ FDEM Survey :members: :undoc-members: +.. automodule:: SimPEG.EM.FDEM.RxFDEM + :show-inheritance: + :members: + :undoc-members: + FDEM Fields ----------- diff --git a/docs/em/api_TDEM.rst b/docs/content/em/api_TDEM.rst similarity index 99% rename from docs/em/api_TDEM.rst rename to docs/content/em/api_TDEM.rst index fe3dc613..4944ca52 100644 --- a/docs/em/api_TDEM.rst +++ b/docs/content/em/api_TDEM.rst @@ -359,7 +359,7 @@ TDEM - B formulation Field Storage ============= -.. autoclass:: SimPEG.EM.TDEM.SurveyTDEM.FieldsTDEM +.. autoclass:: SimPEG.EM.TDEM.BaseTDEM.FieldsTDEM :show-inheritance: :members: :undoc-members: diff --git a/docs/em/api_Utils.rst b/docs/content/em/api_Utils.rst similarity index 100% rename from docs/em/api_Utils.rst rename to docs/content/em/api_Utils.rst diff --git a/docs/content/em/api_basic.rst b/docs/content/em/api_basic.rst new file mode 100644 index 00000000..1113108c --- /dev/null +++ b/docs/content/em/api_basic.rst @@ -0,0 +1,33 @@ +Overview of Electromagnetics in SimPEG +************************************** + + +The API +======= + +Physical Properties +------------------- + +.. autoclass:: SimPEG.EM.Base.EMPropMap + :show-inheritance: + :members: + :undoc-members: + +Problem +------- + +.. autoclass:: SimPEG.EM.Base.BaseEMProblem + :show-inheritance: + :members: + :undoc-members: + + +Survey +------ + +.. autoclass:: SimPEG.EM.Base.BaseEMSurvey + :show-inheritance: + :members: + :undoc-members: + + diff --git a/docs/em/index.rst b/docs/content/em/index.rst similarity index 77% rename from docs/em/index.rst rename to docs/content/em/index.rst index a86ebb69..c94c6fc2 100644 --- a/docs/em/index.rst +++ b/docs/content/em/index.rst @@ -3,22 +3,23 @@ Electromagnetics ================ `SimPEG.EM` uses SimPEG as the framework for the forward and inverse -electromagnetics geophysical problems. +electromagnetics geophysical problems. To solve for predicted data, we follow the framework shown below. The model is what we invert for. This is mapped to a physical property on the simulation mesh. A source which is used to excite the system is specified. Having a model and a source, we can solve Maxwell's equations for fields. We sample these -fields with recievers to give us predicted data. +fields with recievers to give us predicted data. -.. image:: ../images/simpegEM_noMath.png +.. image:: ../../images/simpegEM_noMath.png :scale: 50% .. toctree:: :maxdepth: 2 + api_basic api_FDEM api_TDEM api_Utils diff --git a/docs/examples/DC_Analytic_Dipole.rst b/docs/content/examples/DC_Analytic_Dipole.rst similarity index 87% rename from docs/examples/DC_Analytic_Dipole.rst rename to docs/content/examples/DC_Analytic_Dipole.rst index f3d06058..955ddf10 100644 --- a/docs/examples/DC_Analytic_Dipole.rst +++ b/docs/content/examples/DC_Analytic_Dipole.rst @@ -16,6 +16,6 @@ DC Analytic Dipole from SimPEG import Examples Examples.DC_Analytic_Dipole.run() -.. literalinclude:: ../../SimPEG/Examples/DC_Analytic_Dipole.py +.. literalinclude:: ../../../SimPEG/Examples/DC_Analytic_Dipole.py :language: python :linenos: diff --git a/docs/examples/DC_Forward_PseudoSection.rst b/docs/content/examples/DC_Forward_PseudoSection.rst similarity index 92% rename from docs/examples/DC_Forward_PseudoSection.rst rename to docs/content/examples/DC_Forward_PseudoSection.rst index 4231e944..a59aec60 100644 --- a/docs/examples/DC_Forward_PseudoSection.rst +++ b/docs/content/examples/DC_Forward_PseudoSection.rst @@ -31,6 +31,6 @@ Created by @fourndo from SimPEG import Examples Examples.DC_Forward_PseudoSection.run() -.. literalinclude:: ../../SimPEG/Examples/DC_Forward_PseudoSection.py +.. literalinclude:: ../../../SimPEG/Examples/DC_Forward_PseudoSection.py :language: python :linenos: diff --git a/docs/examples/EM_FDEM_1D_Inversion.rst b/docs/content/examples/EM_FDEM_1D_Inversion.rst similarity index 88% rename from docs/examples/EM_FDEM_1D_Inversion.rst rename to docs/content/examples/EM_FDEM_1D_Inversion.rst index acbc8cdc..3cac55db 100644 --- a/docs/examples/EM_FDEM_1D_Inversion.rst +++ b/docs/content/examples/EM_FDEM_1D_Inversion.rst @@ -21,6 +21,6 @@ Here we will create and run a FDEM 1D inversion. from SimPEG import Examples Examples.EM_FDEM_1D_Inversion.run() -.. literalinclude:: ../../SimPEG/Examples/EM_FDEM_1D_Inversion.py +.. literalinclude:: ../../../SimPEG/Examples/EM_FDEM_1D_Inversion.py :language: python :linenos: diff --git a/docs/examples/EM_FDEM_Analytic_MagDipoleWholespace.rst b/docs/content/examples/EM_FDEM_Analytic_MagDipoleWholespace.rst similarity index 88% rename from docs/examples/EM_FDEM_Analytic_MagDipoleWholespace.rst rename to docs/content/examples/EM_FDEM_Analytic_MagDipoleWholespace.rst index 0e1b2d93..81a4cb00 100644 --- a/docs/examples/EM_FDEM_Analytic_MagDipoleWholespace.rst +++ b/docs/content/examples/EM_FDEM_Analytic_MagDipoleWholespace.rst @@ -21,6 +21,6 @@ Here we plot the magnetic flux density from a harmonic dipole in a wholespace. from SimPEG import Examples Examples.EM_FDEM_Analytic_MagDipoleWholespace.run() -.. literalinclude:: ../../SimPEG/Examples/EM_FDEM_Analytic_MagDipoleWholespace.py +.. literalinclude:: ../../../SimPEG/Examples/EM_FDEM_Analytic_MagDipoleWholespace.py :language: python :linenos: diff --git a/docs/examples/EM_Schenkel_Morrison_Casing.rst b/docs/content/examples/EM_Schenkel_Morrison_Casing.rst similarity index 86% rename from docs/examples/EM_Schenkel_Morrison_Casing.rst rename to docs/content/examples/EM_Schenkel_Morrison_Casing.rst index 55f00168..c82a1ad0 100644 --- a/docs/examples/EM_Schenkel_Morrison_Casing.rst +++ b/docs/content/examples/EM_Schenkel_Morrison_Casing.rst @@ -17,10 +17,13 @@ current inside a steel-cased. The model is based on the Schenkel and Morrison Casing Model, and the results are used in a 2016 SEG abstract by Yang et al. -- Schenkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. +.. code-block:: text + + Schenkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. The model consists of: + - Air: Conductivity 1e-8 S/m, above z = 0 - Background: conductivity 1e-2 S/m, below z = 0 - Casing: conductivity 1e6 S/m @@ -53,6 +56,6 @@ citation would be much appreciated! from SimPEG import Examples Examples.EM_Schenkel_Morrison_Casing.run() -.. literalinclude:: ../../SimPEG/Examples/EM_Schenkel_Morrison_Casing.py +.. literalinclude:: ../../../SimPEG/Examples/EM_Schenkel_Morrison_Casing.py :language: python :linenos: diff --git a/docs/examples/EM_TDEM_1D_Inversion.rst b/docs/content/examples/EM_TDEM_1D_Inversion.rst similarity index 88% rename from docs/examples/EM_TDEM_1D_Inversion.rst rename to docs/content/examples/EM_TDEM_1D_Inversion.rst index 53f6f9ef..dd308472 100644 --- a/docs/examples/EM_TDEM_1D_Inversion.rst +++ b/docs/content/examples/EM_TDEM_1D_Inversion.rst @@ -21,6 +21,6 @@ Here we will create and run a TDEM 1D inversion. from SimPEG import Examples Examples.EM_TDEM_1D_Inversion.run() -.. literalinclude:: ../../SimPEG/Examples/EM_TDEM_1D_Inversion.py +.. literalinclude:: ../../../SimPEG/Examples/EM_TDEM_1D_Inversion.py :language: python :linenos: diff --git a/docs/examples/FLOW_Richards_1D_Celia1990.rst b/docs/content/examples/FLOW_Richards_1D_Celia1990.rst similarity index 95% rename from docs/examples/FLOW_Richards_1D_Celia1990.rst rename to docs/content/examples/FLOW_Richards_1D_Celia1990.rst index d2e01c13..5bad1485 100644 --- a/docs/examples/FLOW_Richards_1D_Celia1990.rst +++ b/docs/content/examples/FLOW_Richards_1D_Celia1990.rst @@ -47,6 +47,6 @@ Here we reproduce the results from Celia1990_ demonstrating the head-based formu from SimPEG import Examples Examples.FLOW_Richards_1D_Celia1990.run() -.. literalinclude:: ../../SimPEG/Examples/FLOW_Richards_1D_Celia1990.py +.. literalinclude:: ../../../SimPEG/Examples/FLOW_Richards_1D_Celia1990.py :language: python :linenos: diff --git a/docs/examples/Inversion_Linear.rst b/docs/content/examples/Inversion_Linear.rst similarity index 89% rename from docs/examples/Inversion_Linear.rst rename to docs/content/examples/Inversion_Linear.rst index d635d8e1..922cf4e0 100644 --- a/docs/examples/Inversion_Linear.rst +++ b/docs/content/examples/Inversion_Linear.rst @@ -21,6 +21,6 @@ Here we go over the basics of creating a linear problem and inversion. from SimPEG import Examples Examples.Inversion_Linear.run() -.. literalinclude:: ../../SimPEG/Examples/Inversion_Linear.py +.. literalinclude:: ../../../SimPEG/Examples/Inversion_Linear.py :language: python :linenos: diff --git a/docs/examples/MT_1D_ForwardAndInversion.rst b/docs/content/examples/MT_1D_ForwardAndInversion.rst similarity index 84% rename from docs/examples/MT_1D_ForwardAndInversion.rst rename to docs/content/examples/MT_1D_ForwardAndInversion.rst index 9646a7eb..79c11cfc 100644 --- a/docs/examples/MT_1D_ForwardAndInversion.rst +++ b/docs/content/examples/MT_1D_ForwardAndInversion.rst @@ -10,7 +10,7 @@ MT: 1D: Inversion -======================= +================= Forward model 1D MT data. Setup and run a MT 1D inversion. @@ -22,6 +22,6 @@ Setup and run a MT 1D inversion. from SimPEG import Examples Examples.MT_1D_ForwardAndInversion.run() -.. literalinclude:: ../../SimPEG/Examples/MT_1D_ForwardAndInversion.py +.. literalinclude:: ../../../SimPEG/Examples/MT_1D_ForwardAndInversion.py :language: python :linenos: diff --git a/docs/examples/MT_3D_Foward.rst b/docs/content/examples/MT_3D_Foward.rst similarity index 85% rename from docs/examples/MT_3D_Foward.rst rename to docs/content/examples/MT_3D_Foward.rst index eaeead7a..a07fbdaf 100644 --- a/docs/examples/MT_3D_Foward.rst +++ b/docs/content/examples/MT_3D_Foward.rst @@ -10,7 +10,7 @@ MT: 3D: Forward -======================= +=============== Forward model 3D MT data. @@ -21,6 +21,6 @@ Forward model 3D MT data. from SimPEG import Examples Examples.MT_3D_Foward.run() -.. literalinclude:: ../../SimPEG/Examples/MT_3D_Foward.py +.. literalinclude:: ../../../SimPEG/Examples/MT_3D_Foward.py :language: python :linenos: diff --git a/docs/examples/Mesh_Basic_ForwardDC.rst b/docs/content/examples/Mesh_Basic_ForwardDC.rst similarity index 89% rename from docs/examples/Mesh_Basic_ForwardDC.rst rename to docs/content/examples/Mesh_Basic_ForwardDC.rst index df18050e..b2660555 100644 --- a/docs/examples/Mesh_Basic_ForwardDC.rst +++ b/docs/content/examples/Mesh_Basic_ForwardDC.rst @@ -20,6 +20,6 @@ Mesh: Basic Forward 2D DC Resistivity from SimPEG import Examples Examples.Mesh_Basic_ForwardDC.run() -.. literalinclude:: ../../SimPEG/Examples/Mesh_Basic_ForwardDC.py +.. literalinclude:: ../../../SimPEG/Examples/Mesh_Basic_ForwardDC.py :language: python :linenos: diff --git a/docs/examples/Mesh_Basic_PlotImage.rst b/docs/content/examples/Mesh_Basic_PlotImage.rst similarity index 88% rename from docs/examples/Mesh_Basic_PlotImage.rst rename to docs/content/examples/Mesh_Basic_PlotImage.rst index a730f303..6761ff7e 100644 --- a/docs/examples/Mesh_Basic_PlotImage.rst +++ b/docs/content/examples/Mesh_Basic_PlotImage.rst @@ -22,6 +22,6 @@ You can use M.PlotImage to plot images on all of the Meshes. from SimPEG import Examples Examples.Mesh_Basic_PlotImage.run() -.. literalinclude:: ../../SimPEG/Examples/Mesh_Basic_PlotImage.py +.. literalinclude:: ../../../SimPEG/Examples/Mesh_Basic_PlotImage.py :language: python :linenos: diff --git a/docs/examples/Mesh_Basic_Types.rst b/docs/content/examples/Mesh_Basic_Types.rst similarity index 89% rename from docs/examples/Mesh_Basic_Types.rst rename to docs/content/examples/Mesh_Basic_Types.rst index 9bbce0e8..4bd4cf7c 100644 --- a/docs/examples/Mesh_Basic_Types.rst +++ b/docs/content/examples/Mesh_Basic_Types.rst @@ -21,6 +21,6 @@ Here we show SimPEG used to create three different types of meshes. from SimPEG import Examples Examples.Mesh_Basic_Types.run() -.. literalinclude:: ../../SimPEG/Examples/Mesh_Basic_Types.py +.. literalinclude:: ../../../SimPEG/Examples/Mesh_Basic_Types.py :language: python :linenos: diff --git a/docs/examples/Mesh_Operators_CahnHilliard.rst b/docs/content/examples/Mesh_Operators_CahnHilliard.rst similarity index 96% rename from docs/examples/Mesh_Operators_CahnHilliard.rst rename to docs/content/examples/Mesh_Operators_CahnHilliard.rst index 9786e911..dd43aa45 100644 --- a/docs/examples/Mesh_Operators_CahnHilliard.rst +++ b/docs/content/examples/Mesh_Operators_CahnHilliard.rst @@ -52,6 +52,6 @@ field separating as the time increases. from SimPEG import Examples Examples.Mesh_Operators_CahnHilliard.run() -.. literalinclude:: ../../SimPEG/Examples/Mesh_Operators_CahnHilliard.py +.. literalinclude:: ../../../SimPEG/Examples/Mesh_Operators_CahnHilliard.py :language: python :linenos: diff --git a/docs/examples/Mesh_QuadTree_Creation.rst b/docs/content/examples/Mesh_QuadTree_Creation.rst similarity index 91% rename from docs/examples/Mesh_QuadTree_Creation.rst rename to docs/content/examples/Mesh_QuadTree_Creation.rst index 5db5a982..d77f6fea 100644 --- a/docs/examples/Mesh_QuadTree_Creation.rst +++ b/docs/content/examples/Mesh_QuadTree_Creation.rst @@ -26,6 +26,6 @@ on an 8x8 mesh (2^3). from SimPEG import Examples Examples.Mesh_QuadTree_Creation.run() -.. literalinclude:: ../../SimPEG/Examples/Mesh_QuadTree_Creation.py +.. literalinclude:: ../../../SimPEG/Examples/Mesh_QuadTree_Creation.py :language: python :linenos: diff --git a/docs/examples/Mesh_QuadTree_FaceDiv.rst b/docs/content/examples/Mesh_QuadTree_FaceDiv.rst similarity index 87% rename from docs/examples/Mesh_QuadTree_FaceDiv.rst rename to docs/content/examples/Mesh_QuadTree_FaceDiv.rst index 6bfdd47f..2ecf154b 100644 --- a/docs/examples/Mesh_QuadTree_FaceDiv.rst +++ b/docs/content/examples/Mesh_QuadTree_FaceDiv.rst @@ -21,6 +21,6 @@ Mesh: QuadTree: FaceDiv from SimPEG import Examples Examples.Mesh_QuadTree_FaceDiv.run() -.. literalinclude:: ../../SimPEG/Examples/Mesh_QuadTree_FaceDiv.py +.. literalinclude:: ../../../SimPEG/Examples/Mesh_QuadTree_FaceDiv.py :language: python :linenos: diff --git a/docs/examples/Mesh_QuadTree_HangingNodes.rst b/docs/content/examples/Mesh_QuadTree_HangingNodes.rst similarity index 91% rename from docs/examples/Mesh_QuadTree_HangingNodes.rst rename to docs/content/examples/Mesh_QuadTree_HangingNodes.rst index 93875478..e1d26b0b 100644 --- a/docs/examples/Mesh_QuadTree_HangingNodes.rst +++ b/docs/content/examples/Mesh_QuadTree_HangingNodes.rst @@ -26,6 +26,6 @@ on an 8x8 mesh (2^3). from SimPEG import Examples Examples.Mesh_QuadTree_HangingNodes.run() -.. literalinclude:: ../../SimPEG/Examples/Mesh_QuadTree_HangingNodes.py +.. literalinclude:: ../../../SimPEG/Examples/Mesh_QuadTree_HangingNodes.py :language: python :linenos: diff --git a/docs/examples/Mesh_Tensor_Creation.rst b/docs/content/examples/Mesh_Tensor_Creation.rst similarity index 94% rename from docs/examples/Mesh_Tensor_Creation.rst rename to docs/content/examples/Mesh_Tensor_Creation.rst index e6cc5b67..ee3af326 100644 --- a/docs/examples/Mesh_Tensor_Creation.rst +++ b/docs/content/examples/Mesh_Tensor_Creation.rst @@ -38,6 +38,6 @@ notation:: from SimPEG import Examples Examples.Mesh_Tensor_Creation.run() -.. literalinclude:: ../../SimPEG/Examples/Mesh_Tensor_Creation.py +.. literalinclude:: ../../../SimPEG/Examples/Mesh_Tensor_Creation.py :language: python :linenos: diff --git a/docs/examples/Utils_surface2ind_topo.rst b/docs/content/examples/Utils_surface2ind_topo.rst similarity index 81% rename from docs/examples/Utils_surface2ind_topo.rst rename to docs/content/examples/Utils_surface2ind_topo.rst index 04b27d5d..5d217562 100644 --- a/docs/examples/Utils_surface2ind_topo.rst +++ b/docs/content/examples/Utils_surface2ind_topo.rst @@ -9,6 +9,10 @@ .. --------------------------------- .. + +Utils: surface2ind_topo +======================= + Here we show how to use :code:`Utils.surface2ind_topo` to identify cells below a topographic surface. @@ -19,6 +23,6 @@ a topographic surface. from SimPEG import Examples Examples.Utils_surface2ind_topo.run() -.. literalinclude:: ../../SimPEG/Examples/Utils_surface2ind_topo.py +.. literalinclude:: ../../../SimPEG/Examples/Utils_surface2ind_topo.py :language: python :linenos: diff --git a/docs/flow/index.rst b/docs/content/flow/index.rst similarity index 94% rename from docs/flow/index.rst rename to docs/content/flow/index.rst index d4299b0d..027376ce 100644 --- a/docs/flow/index.rst +++ b/docs/content/flow/index.rst @@ -35,8 +35,8 @@ Here we reproduce the results from Celia et al. (1990): .. plot:: - from SimPEG.FLOW.Examples import Celia1990 - Celia1990.run() + from SimPEG import Examples + Examples.FLOW_Richards_1D_Celia1990.run() Richards ======== diff --git a/docs/content/ip/index.rst b/docs/content/ip/index.rst new file mode 100644 index 00000000..68def737 --- /dev/null +++ b/docs/content/ip/index.rst @@ -0,0 +1,14 @@ +Induced Polarization +******************** + +Todo: docs for IP! + + +API for IP codes +================ + +.. automodule:: SimPEG.DCIP.BaseIP + :show-inheritance: + :members: + :undoc-members: + :inherited-members: diff --git a/docs/mt/index.rst b/docs/content/mt/index.rst similarity index 100% rename from docs/mt/index.rst rename to docs/content/mt/index.rst diff --git a/docs/credentials.tar.gz.enc b/docs/credentials.tar.gz.enc new file mode 100644 index 00000000..d4798894 Binary files /dev/null and b/docs/credentials.tar.gz.enc differ diff --git a/docs/examples/Inversion_IRLS.rst b/docs/examples/Inversion_IRLS.rst deleted file mode 100644 index 64a072f1..00000000 --- a/docs/examples/Inversion_IRLS.rst +++ /dev/null @@ -1,26 +0,0 @@ -.. _examples_Inversion_IRLS: - -.. --------------------------------- .. -.. .. -.. 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_IRLS.run() - -.. literalinclude:: ../../SimPEG/Examples/Inversion_IRLS.py - :language: python - :linenos: diff --git a/docs/InversionWorkflow-PreSimPEG.png b/docs/images/InversionWorkflow-PreSimPEG.png similarity index 100% rename from docs/InversionWorkflow-PreSimPEG.png rename to docs/images/InversionWorkflow-PreSimPEG.png diff --git a/docs/InversionWorkflow.png b/docs/images/InversionWorkflow.png similarity index 100% rename from docs/InversionWorkflow.png rename to docs/images/InversionWorkflow.png diff --git a/docs/SimPEGFrameworkRevised.png b/docs/images/SimPEGFrameworkRevised.png similarity index 100% rename from docs/SimPEGFrameworkRevised.png rename to docs/images/SimPEGFrameworkRevised.png diff --git a/docs/images/logo-block.ico b/docs/images/logo-block.ico new file mode 100644 index 00000000..91b6a1f1 Binary files /dev/null and b/docs/images/logo-block.ico differ diff --git a/docs/simpeg-framework.png b/docs/images/simpeg-framework.png similarity index 100% rename from docs/simpeg-framework.png rename to docs/images/simpeg-framework.png diff --git a/docs/simpeg-logo.png b/docs/images/simpeg-logo.png similarity index 100% rename from docs/simpeg-logo.png rename to docs/images/simpeg-logo.png diff --git a/docs/index.rst b/docs/index.rst index 0a812ea6..fb6fb4f3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -41,15 +41,16 @@ About SimPEG .. toctree:: :maxdepth: 2 - api_bigPicture - api_installing + content/api_core/api_bigPicture + content/api_core/api_installing Examples ******** .. toctree:: :maxdepth: 2 - api_Examples + + content/api_core/api_Examples Packages ******** @@ -57,9 +58,11 @@ Packages .. toctree:: :maxdepth: 3 - em/index - mt/index - flow/index + content/em/index + content/dc/index + content/ip/index + content/mt/index + content/flow/index Finite Volume ************* @@ -67,7 +70,7 @@ Finite Volume .. toctree:: :maxdepth: 3 - api_FiniteVolume + content/api_core/api_FiniteVolume Forward Problems **************** @@ -75,7 +78,7 @@ Forward Problems .. toctree:: :maxdepth: 3 - api_ForwardProblem + content/api_core/api_ForwardProblem Inversion Components ******************** @@ -83,7 +86,7 @@ Inversion Components .. toctree:: :maxdepth: 3 - api_InversionComponents + content/api_core/api_InversionComponents Utility Codes ************* @@ -91,7 +94,7 @@ Utility Codes .. toctree:: :maxdepth: 3 - api_Utilities + content/api_core/api_Utilities Project Index & Search diff --git a/docs/index.yaml b/docs/index.yaml new file mode 100644 index 00000000..a3b9e05e --- /dev/null +++ b/docs/index.yaml @@ -0,0 +1,11 @@ +indexes: + +# AUTOGENERATED + +# This index.yaml is automatically updated whenever the dev_appserver +# detects that a new type of query is run. If you want to manage the +# index.yaml file manually, remove the above marker line (the line +# saying "# AUTOGENERATED"). If you want to manage some indexes +# manually, move them above the marker line. The index.yaml file is +# automatically uploaded to the admin console when you next deploy +# your application using appcfg.py. diff --git a/docs/simpegdocs.py b/docs/simpegdocs.py new file mode 100644 index 00000000..002df6bd --- /dev/null +++ b/docs/simpegdocs.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python +# +# Copyright 2007 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import cgi +import datetime +import webapp2 +import logging + +from google.appengine.ext import ndb +from google.appengine.api import users +from google.appengine.api import mail +from google.appengine.api import urlfetch + +import os +import jinja2 +import urllib, hashlib +import json + +TEMPLATEFOLDER = '_build/html/' + +JINJA_ENVIRONMENT = jinja2.Environment( + loader=jinja2.FileSystemLoader(os.path.join(os.path.dirname(__file__).split('/')[:-1])), + extensions=['jinja2.ext.autoescape'], + autoescape=False) + +def setTemplate(self, template_values, templateFile, _templateFolder=TEMPLATEFOLDER): + # add Defaults + template_values['_templateFolder'] = _templateFolder + template_values['_year'] = str(datetime.datetime.now().year) + path = os.path.normpath(_templateFolder+templateFile) + template = JINJA_ENVIRONMENT.get_template(path) + resp = self.response.write(template.render(template_values)) + + # if resp is None: + # self.redirect('/error.html', permanent=True) + +class Images(webapp2.RequestHandler): + def get(self): + self.redirect('/'+self.request.path) + +class Redirect(webapp2.RequestHandler): + def get(self): + path = str(self.request.path).split(os.path.sep)[3:] + self.redirect(('/%s'%os.path.sep.join(path)), permanent=True) + + +class MainPage(webapp2.RequestHandler): + def get(self): + setTemplate(self, {"indexPage":True}, 'index.html') + +# class Error(webapp2.RequestHandler): +# def get(self): +# setTemplate(self, {}, 'error.html', _templateFolder='_templates/') +# # self.redirect('/error.html', permanent=True) + +from webapp2 import Route, RedirectHandler +# pointers = [ +# Route('/en/latest/.*', RedirectHandler, defaults={'_uri': '/.*'}), +# # Route('/en/latest', RedirectHandler, defaults={'_uri': '/en/latest/'}), +# Route('/en/latest/', RedirectHandler, defaults={'_uri': '/'}), +# +# ('/.*', MainPage), +# ('/', MainPage), +# ('', MainPage), +# ('/_images/.*', Images), +# ] + +app = webapp2.WSGIApplication([ + ('/_images/.*', Images), + ('/en/latest/.*',Redirect), + ('/', MainPage), + # ('/.*', Error), +], debug=True) + + +# app.error_handlers[404] = Error + diff --git a/setup.py b/setup.py index 5308db47..06cd9b27 100644 --- a/setup.py +++ b/setup.py @@ -83,7 +83,7 @@ with open("README.rst") as f: setup( name = "SimPEG", - version = "0.1.10", + version = "0.1.11", packages = find_packages(), install_requires = ['numpy>=1.7', 'scipy>=0.13', diff --git a/tests/base/test_maps.py b/tests/base/test_maps.py index 19cd4e77..6b1c1ad7 100644 --- a/tests/base/test_maps.py +++ b/tests/base/test_maps.py @@ -5,8 +5,8 @@ from scipy.sparse.linalg import dsolve TOL = 1e-14 -MAPS_TO_TEST_2D = ["CircleMap", "ComplexMap", "ExpMap", "IdentityMap", "SurjectVertical1D", "Weighting", "SurjectFull","FullMap","Vertical1DMap"] -MAPS_TO_TEST_3D = [ "ComplexMap", "ExpMap", "IdentityMap", "SurjectVertical1D", "Weighting", "SurjectFull","FullMap","Vertical1DMap"] +MAPS_TO_TEST_2D = ["CircleMap", "ComplexMap", "ExpMap", "IdentityMap", "SurjectVertical1D", "Weighting", "SurjectFull","FullMap"] +MAPS_TO_TEST_3D = [ "ComplexMap", "ExpMap", "IdentityMap", "SurjectVertical1D", "Weighting", "SurjectFull","FullMap"] class MapTests(unittest.TestCase): diff --git a/tests/docs/test_docs.py b/tests/docs/test_docs.py new file mode 100644 index 00000000..9b986632 --- /dev/null +++ b/tests/docs/test_docs.py @@ -0,0 +1,43 @@ +import subprocess +import unittest +import os + +class Doc_Test(unittest.TestCase): + + @property + def path_to_docs(self): + dirname, filename = os.path.split(os.path.abspath(__file__)) + return os.path.sep.join(dirname.split(os.path.sep)[:-2] + ['docs']) + + def test_html(self): + doctrees_path = os.path.sep.join(self.path_to_docs.split(os.path.sep) + ['_build']+['doctrees']) + html_path = os.path.sep.join(self.path_to_docs.split(os.path.sep) + ['_build']+['html']) + + check = subprocess.call(["sphinx-build", "-nW", "-b", "html", "-d", + "%s"%(doctrees_path) , + "%s"%(self.path_to_docs), + "%s"%(html_path)]) + assert check == 0 + + # def test_latex(self): + # doctrees_path = os.path.sep.join(self.path_to_docs.split(os.path.sep) + ['_build']+['doctrees']) + # latex_path = os.path.sep.join(self.path_to_docs.split(os.path.sep) + ['_build']+['latex']) + + # check = subprocess.call(["sphinx-build", "-nW", "-b", "latex", "-d", + # "%s"%(doctrees_path), + # "%s"%(self.path_to_docs), + # "%s"%(latex_path)]) + # assert check == 0 + + # def test_linkcheck(self): + # doctrees_path = os.path.sep.join(self.path_to_docs.split(os.path.sep) + ['_build']+['doctrees']) + # link_path = os.path.sep.join(self.path_to_docs.split(os.path.sep) + ['_build']) + + # check = subprocess.call(["sphinx-build", "-nW", "-b", "linkcheck", "-d", + # "%s"%(doctrees_path), + # "%s"%(self.path_to_docs), + # "%s"%(link_path)]) + # assert check == 0 + +if __name__ == '__main__': + unittest.main()