Source code for pygimli.physics.gravimetry.MagneticsModelling

"""Magnetics forward operator."""
import numpy as np
import pygimli as pg
from .kernel import SolveGravMagHolstein


[docs] class MagneticsModelling(pg.frameworks.MeshModelling): """ Magnetics modelling operator using Holstein (2007). """
[docs] def __init__(self, mesh=None, points=None, cmp=["TFA"], igrf=[0, 0, 50000]): """ Setup forward operator. Parameters ---------- mesh: pygimli:mesh Tetrahedral or hexahedral mesh. points: list|array of (x, y, z) Measuring points. cmp: [str,] Component of: gx, gy, gz, TFA, Bx, By, Bz, Bxy, Bxz, Byy, Byz, Bzz igrf: list|array of size 3 or 7 International geomagnetic reference field. either: * [D, I, H, X, Y, Z, F] - declination, inclination, horizontal field, X/Y/Z components, total field OR * [X, Y, Z] - X/Y/Z components OR * [lat, lon] - latitude, longitude (automatic by pyIGRF) """ # check if components do not contain g! super().__init__() self._refineH2 = False # self.createRefinedForwardMesh(refine=False, pRefine=False) self.mesh_ = mesh self.sensorPositions = points self.components = cmp self.igrf = None if hasattr(igrf, "__iter__"): if len(igrf) == 2: # lat lon pyIGRF = pg.optImport('pyIGRF', requiredFor="use igrf support" f" for {self.__class__.__name__}. " "Please install pyIGRF with: pip install pyIGRF") self.igrf = pyIGRF.igrf_value(*igrf) else: # 3 (x,y,z) or 7 (T,H,X,Y,Z,D,I) self.igrf = igrf self.kernel = None self.J = pg.matrix.BlockMatrix() if self.mesh_ is not None: self.setMesh(self.mesh_)
[docs] def computeKernel(self): """ Compute the kernel. """ points = np.column_stack([self.sensorPositions[:, 1], self.sensorPositions[:, 0], -np.abs(self.sensorPositions[:, 2])]) self.kernel = SolveGravMagHolstein(self.mesh().NED(), pnts=points, igrf=self.igrf, cmp=self.components) self.J = pg.matrix.BlockMatrix() self.Ki = [] self.Ji = [] for iC in range(self.kernel.shape[1]): self.Ki.append(np.squeeze(self.kernel[:, iC, :])) self.Ji.append(pg.matrix.NumpyMatrix(self.Ki[-1])) self.J.addMatrix(self.Ji[-1], iC*self.kernel.shape[0], 0) self.J.recalcMatrixSize() self.setJacobian(self.J)
[docs] def response(self, model): """ Compute forward response. Arguments --------- model: array-like Model parameters. """ if self.kernel is None: self.computeKernel() return self.J.dot(model)
[docs] def createJacobian(self, model): """ Do nothing as this is a linear problem. Abstract method to create the Jacobian matrix. Need to be implemented in derived classes. Arguments --------- model: array-like Model parameters. """
# any defaults possible?
[docs] class RemanentMagneticsModelling(MagneticsModelling):
[docs] def __init__(self, mesh, points, cmp=["Bx", "By", "Bz"], igrf=[0, 0, 50000]): self.mesh_ = mesh self.mesh_["marker"] = 0 super().__init__(mesh=self.mesh_, points=points, igrf=igrf, cmp=cmp) self.magX = MagneticsModelling(self.mesh_, points, igrf=[1, 0, 0], cmp=cmp) self.magX.computeKernel() self.magY = MagneticsModelling(self.mesh_, points, igrf=[0, 1, 0], cmp=cmp) self.magY.computeKernel() self.magZ = MagneticsModelling(self.mesh_, points, igrf=[0, 0, 1], cmp=cmp) self.magZ.computeKernel() self.m1 = pg.Mesh(self._baseMesh) self.m2 = pg.Mesh(self._baseMesh) self.regionManager().addRegion(1, self.m1, 0) self.regionManager().addRegion(2, self.m2, 0) self.J = pg.matrix.hstack([self.magX.jacobian(), self.magY.jacobian(), self.magZ.jacobian()]) self.J.recalcMatrixSize() self.setJacobian(self.J)
[docs] def createJacobian(self, model): """Do nothing.""" pass
[docs] def response(self, model): """Add together all three responses.""" modelXYZ = np.reshape(model, [3, -1]) return (self.magX.response(modelXYZ[0]) + self.magY.response(modelXYZ[1]) + self.magZ.response(modelXYZ[2])) * 4e-7 * np.pi * 1e9