PageRenderTime 58ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/tutorials/Tutorial_3_kernel.py

https://gitlab.com/Skibbe/comet
Python | 116 lines | 30 code | 11 blank | 75 comment | 3 complexity | 19bf357a233ca2735ee950539540e601 MD5 | raw file
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. Tutorial 3
  5. Kernel-class
  6. After importing/defining everything in the Survey and FID classes the kernel
  7. class is used for the computation of the kernel functions.
  8. If a simple synthetic case is constructed the class is never seen, however
  9. to know how it works and what it does really helps to understand how COMET is
  10. working.
  11. """
  12. # comet packages
  13. from comet import pyhed as ph
  14. from comet import snmr
  15. # numerics
  16. import numpy as np
  17. # plotting
  18. import matplotlib.pyplot as plt
  19. if __name__ == '__main__':
  20. # set log level to 20 == Info level
  21. ph.log.setLevel(20)
  22. # %%
  23. # Quickly initialize some default stuff covered by the first two tutorials
  24. # =========================================================================
  25. # three half overlapping loops, 1D earth + earth magnetic field
  26. # init all 9 combinations for FID's
  27. loop0 = ph.loop.buildRectangle([[-40, -20], [0, 20]], max_length=2)
  28. loop1 = ph.loop.buildRectangle([[-20, -20], [20, 20]], max_length=2)
  29. loop2 = ph.loop.buildRectangle([[0, -20], [40, 20]], max_length=2)
  30. site = snmr.survey.Survey()
  31. site.addLoop([loop0, loop1, loop2])
  32. site.setEarth(mag=48000e-9, incl=60, decl=0)
  33. config = ph.config(rho=[1000, 10], d=[10], f=site.earth.larmor)
  34. site.setLoopConfig(config)
  35. for tx_i in range(3):
  36. for rx_i in range(3):
  37. site.createSounding(tx=tx_i, rx=rx_i)
  38. # %%
  39. # Now the kernel class
  40. # =========================================================================
  41. # get 1D kernel for the first fid
  42. kern = site.createKernel(fid=0, dimension=1)
  43. # that's basically all you need to generate a valid working kernel class
  44. # let's take a look
  45. print(kern)
  46. # The kernel class itself has only references to the survey, loops and FID
  47. # Changes of parameters like pulses, loop turns etc are made there and
  48. # piped to the kernel.
  49. # However the kernel class comes with some features too.
  50. # The z discretization for a 1D kernel for example.
  51. kern.createZVector(90, -60, min_thk=0.5)
  52. # z-vector in 90 steps up to 60 meter depth.
  53. # the layers are spaced using a sinus hyperbolicus function (more linear
  54. # compared to log, which is nicer in larger depth)
  55. # The min_thk specifies the thickness of the final kernel discretization.
  56. # Small layers around z = 0 are combined until each layer is at least 0.5
  57. # thick. That is nice for inversions later. The kernel values are summed up
  58. # for the small thicknesses to have a more accurate kernel function in the
  59. # swallow subsurface.
  60. # Bye the way kern.setZVector() is also possible.
  61. # With this a mesh can be generated.
  62. # The mesh generation tool has a lot of flexibility, however
  63. # we will explain the different values elsewhere, here we just build the
  64. # default mesh.
  65. kern.create1DKernelMesh()
  66. # with this discretization we can calculate the kernel function
  67. # we will allow the usage of up to 4 CPUs (depending on the hardware)
  68. kern.calculate(num_cpu=4)
  69. # if we do this right here, the kernel is requesting a magnetic field
  70. # first, however there is none. Following the principle of supply and
  71. # demand, the magnetic field calculation routine of the loop (in this case)
  72. # loop 0 tries to get a magnetic field. Next thing, there is no mesh yet,
  73. # so further traceback will result in the creation of a mesh for the first
  74. # loop in order to calculate a magnetic field.
  75. # So with calling "kern.calculate(num_cpu=4)" first a mesh of loop 0, then
  76. # a magnetic field and last a kernel for FID 0 is computed.
  77. # In fact even the manual call of "kern.create1DKernelMesh()"
  78. # or even "kern.createZVector(...)" is not needed, however internally only
  79. # the default input parameter are used, which in some cases may not b
  80. # enough.
  81. # overview in the console
  82. print(kern)
  83. # and show
  84. kern.show(toplot=['real', 'imag', '0D'])
  85. # Save and load
  86. # =========================================================================
  87. kern.save(savename='kern_fid_0')
  88. # saves kernel class including mesh and kernel matrix, but excluding survey
  89. # and FID (just the references are saved == indices to the correct loops
  90. # and the FID). A backup of the pulse moments is saved with the kernel but
  91. # discarded once the survey is loaded and connected back to the kernel.
  92. kern2 = snmr.kernel.Kernel(name='kern_fid_0')
  93. print(kern2)
  94. # you see an empty survey class and a None as FID!, no loops are known
  95. # plotting would be possible, inversions too, but a recalculation would
  96. # fail
  97. # Let's fix this by reconnecting with survey and FID
  98. kern2.setSurvey(site, fid=0)
  99. print(kern2)
  100. # now we are back online, "kern2" is now basically exact the same as "kern"
  101. plt.show()
  102. # The End