PageRenderTime 26ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/python/pybert/fdip/sipmodelling.py

https://gitlab.com/resistivity-net/bert
Python | 158 lines | 120 code | 23 blank | 15 comment | 19 complexity | d98bf9a5aa21e0c3bb4c06d96119a8d9 MD5 | raw file
  1. from math import pi
  2. import numpy as np
  3. import pygimli as pg
  4. import pybert as pb
  5. try:
  6. from pygimli import ModellingBase
  7. except:
  8. from pygimli.core import ModellingBase
  9. # RhoAC = RhoDC * (1-m) ==> dRhoa / m = dRhoa/dRho * dRho/m = JDC * (-RhoDC)
  10. class DCIPMModelling(ModellingBase):
  11. """ DC/IP modelling class using an (FD-based) approach """
  12. def __init__(self, f, mesh, rho, verbose=False):
  13. """ init class with DC forward operator and resistivity vector """
  14. super().__init__(verbose=verbose)
  15. self.setMesh(mesh)
  16. self.f = f
  17. self.rho = rho # DC resistivity
  18. self.mrho = -self.rho
  19. self.rhoa = f.response(self.rho)
  20. self.drhoa = -1.0 / self.rhoa
  21. self.J = pg.matrix.MultLeftRightMatrix(f.jacobian(),
  22. self.drhoa, self.mrho)
  23. self.setJacobian(self.J)
  24. def response(self, m):
  25. """ return forward response as function of chargeability model """
  26. rho = self.rho * (1. - m)
  27. if self.verbose:
  28. print('min/max m=', min(m), max(m), end=" ")
  29. print('min/max rho=', min(rho), max(rho), end=" ")
  30. ma = 1.0 - self.f.response(rho) / self.rhoa
  31. if self.verbose:
  32. print('min/max ma=', min(ma), max(ma))
  33. return ma + 1e-4
  34. def createJacobian(self, model):
  35. """ create jacobian matrix using unchanged DC jacobian and m model """
  36. pass # do nothing (but prevent brute-force jacobian calculation)
  37. # self.J.left = - model * 1.0 # prevent reference change
  38. class ERTTLmod(ModellingBase):
  39. """ ERT timelapse modelling class based on BlockMatrices """
  40. def __init__(self, nf=0, data=None, mesh=None, fop=None, rotate=False,
  41. set1back=True, verbose=False):
  42. """ Parameters: """
  43. super(type(self), self).__init__(verbose)
  44. if fop is not None:
  45. data = fop.data()
  46. mesh = fop.mesh()
  47. if type(data) == list: # list of data with different size
  48. nf = len(data)
  49. self.nf = nf
  50. self.nd = []
  51. self.FOP2d = []
  52. for i in range(nf):
  53. if type(data) is list:
  54. fopi = pb.DCSRMultiElectrodeModelling(mesh, data[i])
  55. else:
  56. fopi = pb.DCSRMultiElectrodeModelling(mesh, data)
  57. self.nd.append(fopi.data().size())
  58. if set1back:
  59. fopi.region(1).setBackground(True)
  60. fopi.createRefinedForwardMesh(True)
  61. self.FOP2d.append(fopi)
  62. self.id = np.hstack((0, np.cumsum(self.nd, dtype=np.int64))) # indices
  63. self.pd2d = pg.Mesh(self.FOP2d[0].regionManager().paraDomain())
  64. print("2D PD:", self.pd2d)
  65. for c in self.pd2d.cells():
  66. c.setMarker(0)
  67. self.nc = self.pd2d.cellCount()
  68. self.J = pg.core.RBlockMatrix()
  69. for i in range(nf):
  70. n = self.J.addMatrix(self.FOP2d[i].jacobian())
  71. self.J.addMatrixEntry(n, int(self.id[i]), self.nc*i)
  72. z = pg.Vector(range(nf+1))
  73. self.mesh3D = pg.core.createMesh3D(self.pd2d, z, 0, 0)
  74. if rotate:
  75. self.mesh3D.swapCoordinates(1,2)
  76. # self.mesh3D.rotate(pg.Pos(pi/2, 0, 0))
  77. self.mesh3D.exportVTK('mesh3d.vtk')
  78. self.setMesh(self.mesh3D)
  79. print("3D PD:", self.mesh3D)
  80. if 0: # maybe skip it so that it will force recalc in 1st iteration
  81. self.FOP2d[0].jacobian().resize(data.size(), self.nc)
  82. self.FOP2d[-1].jacobian().resize(data.size(), self.nc)
  83. self.J.recalcMatrixSize()
  84. print(self.J.rows(), self.J.cols())
  85. self.setJacobian(self.J)
  86. def response(self, model):
  87. """ cut-together forward responses of all soundings """
  88. resp = pg.Vector(int(self.id[-1]))
  89. for i in range(self.nf):
  90. resp.setVal(self.FOP2d[i].response(
  91. model[self.nc*i:self.nc*(i+1)]),
  92. int(self.id[i]), int(self.id[i+1]))
  93. return resp
  94. def createJacobian(self, model):
  95. """Compute Jacobian matrix by individual (block) Jacobians."""
  96. for i in range(self.nf):
  97. self.FOP2d[i].createJacobian(model[self.nc*i:self.nc*(i+1)])
  98. class ERTMultiPhimod(ModellingBase):
  99. """ FDEM 2d-LCI modelling class based on BlockMatrices """
  100. def __init__(self, pd, J2d, nf, rotate=False, verbose=False):
  101. """ Parameters: FDEM data class and number of layers """
  102. super(ERTMultiPhimod, self).__init__(verbose)
  103. self.nf = nf
  104. self.mesh2d = pd
  105. self.pd2d = pd
  106. self.nc = pd.cellCount()
  107. for c in self.pd2d.cells():
  108. c.setMarker(0)
  109. self.nd = J2d.rows()
  110. self.J2d = J2d
  111. self.FOP2d = pg.core.LinearModelling(pd, J2d)
  112. self.J = pg.core.RBlockMatrix()
  113. for i in range(self.nf):
  114. n = self.J.addMatrix(self.J2d)
  115. self.J.addMatrixEntry(n, self.nd*i, self.nc*i)
  116. z = pg.Vector(range(nf+1))
  117. self.mesh3D = pg.core.createMesh3D(self.pd2d, z, 0, 0)
  118. if rotate:
  119. self.mesh3D.swapCoordinates(1, 2) # interchange y/z for zWeight
  120. # self.mesh3D.rotate(pg.Pos(pi/2, 0, 0))
  121. self.setMesh(self.mesh3D)
  122. print(self.nd*self.nf, self.nc*self.nf, self.mesh3D.cellCount())
  123. self.J.recalcMatrixSize()
  124. print(self.J.rows(), self.J.cols())
  125. self.setJacobian(self.J)
  126. def response(self, model):
  127. """ cut-together forward responses of all soundings """
  128. resp = pg.Vector(self.nd*self.nf)
  129. for i in range(self.nf):
  130. modeli = model[self.nc*i:self.nc*(i+1)]
  131. resp.setVal(self.J2d * modeli,
  132. self.nd*i, self.nd*(i+1))
  133. return resp
  134. def createJacobian(self, model):
  135. pass