Source code for pygimli.frameworks.lsqrinversion

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from math import sqrt
import numpy as np
import pygimli as pg
from pygimli.frameworks import Inversion
from pygimli.solver.leastsquares import lsqr as lssolver
from .linesearch import lineSearch


[docs] class LSQRInversion(Inversion): """LSQR solver based inversion"""
[docs] def __init__(self, *args, **kwargs): """Init.""" super().__init__(*args, **kwargs) self.G = None self.c = None self.my = 1.0 self.LSQRiter = 200
[docs] def setParameterConstraints(self, G, c, my=1.0): """Set parameter constraints G*p=c.""" self.G = G self.c = c self.my = my
[docs] def oneStep(self): """One inversion step.""" pg.verbose("Running LSQR inversion step!") model = self.model if len(self.response) != len(self.dataVals): self.setResponse(self.fop.response(model)) self.fop.createJacobian(model) # self.checkTransFunctions() tD = self.dataTrans tM = self.modelTrans nData = len(self.dataVals) self.A = pg.BlockMatrix() # to be filled with scaled J and C matrices # part 1: data part J = self.fop.jacobian() self.dScale = 1.0 / pg.log(self.errorVals+1.0) self.leftJ = tD.deriv(self.response) * self.dScale # self.leftJ = self.dScale / tD.deriv(self.response()) self.rightJ = 1.0 / tM.deriv(model) self.JJ = pg.matrix.MultLeftRightMatrix(J, self.leftJ, self.rightJ) # self.A.addMatrix(self.JJ, 0, 0) self.mat1 = self.A.addMatrix(self.JJ) self.A.addMatrixEntry(self.mat1, 0, 0) # part 2: normal constraints # self.checkConstraints() self.C = self.fop.constraints() self.leftC = pg.Vector(self.C.rows(), 1.0) self.rightC = pg.Vector(self.C.cols(), 1.0) self.CC = pg.matrix.MultLeftRightMatrix(self.C, self.leftC, self.rightC) self.mat2 = self.A.addMatrix(self.CC) lam = self.lam self.A.addMatrixEntry(self.mat2, nData, 0, sqrt(lam)) # % part 3: parameter constraints if self.G is not None: self.rightG = 1.0 / tM.deriv(model) self.GG = pg.matrix.MultRightMatrix(self.G, self.rightG) self.mat3 = self.A.addMatrix(self.GG) nConst = self.C.rows() self.A.addMatrixEntry(self.mat3, nData+nConst, 0, sqrt(self.my)) self.A.recalcMatrixSize() # right-hand side vector deltaD = (tD.fwd(self.dataVals)-tD.fwd(self.response)) * self.dScale deltaC = -(self.CC * tM.fwd(model) * sqrt(lam)) deltaC *= 1.0 - self.inv.localRegularization() # oper. on DeltaM only rhs = pg.cat(deltaD, deltaC) if self.G is not None: deltaG = (self.c - self.G * model) * sqrt(self.my) rhs = pg.cat(pg.cat(deltaD, deltaC), deltaG) dM = lssolver(self.A, rhs, maxiter=self.LSQRiter, verbose=self.verbose) tau, responseLS = lineSearch(self, dM) pg.debug(f"tau={tau}") self.model = tM.update(self.model, dM*tau) if tau == 1.0: self.inv.setResponse(responseLS) else: # compute new response self.inv.setResponse(self.fop.response(self.model)) # self.inv.setLambda(self.lam * self.inv.lambdaFactor()) self.inv.setModel(self.model) return True
if __name__ == '__main__': nlay = 4 # number of layers lam = 200. # (initial) regularization parameter errPerc = 3. # relative error of 3 percent ab2 = np.logspace(-1, 2, 50) # AB/2 distance (current electrodes) mn2 = ab2 / 3. # MN/2 distance (potential electrodes) f = pg.physics.ves.VESModelling(ab2=ab2, mn2=mn2, nLayers=nlay) synres = [100., 500., 20., 800.] # synthetic resistivity synthk = [0.5, 3.5, 6.] # synthetic thickness (nlay-th layer is infinite) rhoa = f(synthk+synres) rhoa = rhoa * (pg.randn(len(rhoa)) * errPerc / 100. + 1.) tLog = pg.trans.TransLog() inv = LSQRInversion(fop=f, verbose=True) inv.LSQRiter = 20 inv.dataTrans = tLog inv.modelTrans = tLog startModel = pg.cat(pg.Vector(nlay-1, 5), pg.Vector(nlay, pg.median(rhoa))) inv.inv.setMarquardtScheme() # unconstrained model1 = inv.run(rhoa, pg.Vector(len(rhoa), errPerc/100), lam=1000, startModel=startModel) print(model1) # constrained G = pg.Matrix(rows=1, cols=len(startModel)) for i in range(3): G.setVal(0, i, 1) c = pg.Vector(1, pg.sum(synthk)) inv.setParameterConstraints(G, c, 100) model2 = inv.run(rhoa, pg.Vector(len(rhoa), errPerc/100), lam=1000, startModel=startModel) print(model2) print(inv.chi2(), inv.relrms(), pg.sum(inv.model[:nlay-1])) # %% fig, ax = pg.plt.subplots() ax.loglog(rhoa, ab2, "x") ax.loglog(inv.response, ab2, "-") # %% fig, ax = pg.plt.subplots() pg.viewer.mpl.drawModel1D(ax, synthk, synres, plot="semilogx", label="synth") pg.viewer.mpl.drawModel1D(ax, model=model1, label="unconstrained") pg.viewer.mpl.drawModel1D(ax, model=model2, label="constrained") ax.set_ylim(15, 0) ax.grid(True) ax.legend();