pygmi 2.2.7__zip

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. pygmi-2.2.7/LICENSE.txt +623 -0
  2. pygmi-2.2.7/MANIFEST.in +7 -0
  3. pygmi-2.2.7/PKG-INFO +47 -0
  4. pygmi-2.2.7/README.md +55 -0
  5. pygmi-2.2.7/README.rst +20 -0
  6. pygmi-2.2.7/log.txt +242 -0
  7. pygmi-2.2.7/pygmi/__init__.py +22 -0
  8. pygmi-2.2.7/pygmi/clust/__init__.py +4 -0
  9. pygmi-2.2.7/pygmi/clust/crisp_clust.py +708 -0
  10. pygmi-2.2.7/pygmi/clust/datatypes.py +65 -0
  11. pygmi-2.2.7/pygmi/clust/fuzzy_clust.py +906 -0
  12. pygmi-2.2.7/pygmi/clust/graphs.py +421 -0
  13. pygmi-2.2.7/pygmi/clust/graphtool.py +667 -0
  14. pygmi-2.2.7/pygmi/clust/menu.py +139 -0
  15. pygmi-2.2.7/pygmi/clust/var_ratio.py +92 -0
  16. pygmi-2.2.7/pygmi/clust/xie_beni.py +93 -0
  17. pygmi-2.2.7/pygmi/helpdocs/linepointer.png +0 -0
  18. pygmi-2.2.7/pygmi/helpdocs/pygmi.main.html +31 -0
  19. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.ddisp.html +15 -0
  20. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.iodefs.exportkmz.html +13 -0
  21. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.iodefs.importpicture.html +16 -0
  22. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.layer.html +17 -0
  23. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.mext.html +44 -0
  24. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.misc.rangedcopy.html +16 -0
  25. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.param.html +37 -0
  26. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.prof.html +32 -0
  27. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.pview.html +26 -0
  28. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.gradients.html +14 -0
  29. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.tilt.html +14 -0
  30. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.visibility.html +14 -0
  31. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datagrid.html +13 -0
  32. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datamerge.html +11 -0
  33. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datareproj.html +11 -0
  34. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.rtp.html +14 -0
  35. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.ginterp.html +31 -0
  36. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.igrf.html +20 -0
  37. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.normalisation.html +14 -0
  38. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.smooth.html +22 -0
  39. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.tiltdepth.html +20 -0
  40. pygmi-2.2.7/pygmi/images/Help.png +0 -0
  41. pygmi-2.2.7/pygmi/images/bringtofront.png +0 -0
  42. pygmi-2.2.7/pygmi/images/cgs2.emf +0 -0
  43. pygmi-2.2.7/pygmi/images/delete.png +0 -0
  44. pygmi-2.2.7/pygmi/images/linepointer.png +0 -0
  45. pygmi-2.2.7/pygmi/images/logo256.ico +0 -0
  46. pygmi-2.2.7/pygmi/images/logo256.png +0 -0
  47. pygmi-2.2.7/pygmi/images/pointer.png +0 -0
  48. pygmi-2.2.7/pygmi/images/pygmi.png +0 -0
  49. pygmi-2.2.7/pygmi/images/sendtoback.png +0 -0
  50. pygmi-2.2.7/pygmi/main.py +1037 -0
  51. pygmi-2.2.7/pygmi/menu_default.py +327 -0
  52. pygmi-2.2.7/pygmi/misc.py +147 -0
  53. pygmi-2.2.7/pygmi/pfmod/__init__.py +6 -0
  54. pygmi-2.2.7/pygmi/pfmod/cubes.py +1488 -0
  55. pygmi-2.2.7/pygmi/pfmod/datatypes.py +292 -0
  56. pygmi-2.2.7/pygmi/pfmod/grvmag3d.py +1265 -0
  57. pygmi-2.2.7/pygmi/pfmod/iodefs.py +1001 -0
  58. pygmi-2.2.7/pygmi/pfmod/menu.py +107 -0
  59. pygmi-2.2.7/pygmi/pfmod/misc.py +301 -0
  60. pygmi-2.2.7/pygmi/pfmod/pfmod.py +248 -0
  61. pygmi-2.2.7/pygmi/pfmod/tab_ddisp.py +425 -0
  62. pygmi-2.2.7/pygmi/pfmod/tab_layer.py +490 -0
  63. pygmi-2.2.7/pygmi/pfmod/tab_mext.py +544 -0
  64. pygmi-2.2.7/pygmi/pfmod/tab_param.py +548 -0
  65. pygmi-2.2.7/pygmi/pfmod/tab_prof.py +946 -0
  66. pygmi-2.2.7/pygmi/pfmod/tab_pview.py +740 -0
  67. pygmi-2.2.7/pygmi/raster/IGRF11.COF +1635 -0
  68. pygmi-2.2.7/pygmi/raster/__init__.py +14 -0
  69. pygmi-2.2.7/pygmi/raster/cooper.py +718 -0
  70. pygmi-2.2.7/pygmi/raster/dataprep.py +1640 -0
  71. pygmi-2.2.7/pygmi/raster/datatypes.py +123 -0
  72. pygmi-2.2.7/pygmi/raster/equation_editor.py +256 -0
  73. pygmi-2.2.7/pygmi/raster/ginterp.py +1901 -0
  74. pygmi-2.2.7/pygmi/raster/graphs.py +531 -0
  75. pygmi-2.2.7/pygmi/raster/igrf.py +860 -0
  76. pygmi-2.2.7/pygmi/raster/iodefs.py +813 -0
  77. pygmi-2.2.7/pygmi/raster/menu.py +307 -0
  78. pygmi-2.2.7/pygmi/raster/normalisation.py +187 -0
  79. pygmi-2.2.7/pygmi/raster/show_table.py +245 -0
  80. pygmi-2.2.7/pygmi/raster/smooth.py +406 -0
  81. pygmi-2.2.7/pygmi/raster/tiltdepth.py +590 -0
  82. pygmi-2.2.7/pygmi/seis/__init__.py +0 -0
  83. pygmi-2.2.7/pygmi/seis/beachball.py +751 -0
  84. pygmi-2.2.7/pygmi/seis/datatypes.py +605 -0
  85. pygmi-2.2.7/pygmi/seis/del_rec.py +410 -0
  86. pygmi-2.2.7/pygmi/seis/iodefs.py +1261 -0
  87. pygmi-2.2.7/pygmi/seis/menu.py +136 -0
  88. pygmi-2.2.7/pygmi/seis/scan_imp.py +795 -0
  89. pygmi-2.2.7/pygmi/test/__init__.py +6 -0
  90. pygmi-2.2.7/pygmi/test/pfmod.py +212 -0
  91. pygmi-2.2.7/pygmi/test/tests.py +39 -0
  92. pygmi-2.2.7/pygmi/vector/__init__.py +7 -0
  93. pygmi-2.2.7/pygmi/vector/datatypes.py +74 -0
  94. pygmi-2.2.7/pygmi/vector/graphs.py +443 -0
  95. pygmi-2.2.7/pygmi/vector/iodefs.py +345 -0
  96. pygmi-2.2.7/pygmi/vector/menu.py +127 -0
  97. pygmi-2.2.7/pygmi.egg-info/PKG-INFO +47 -0
  98. pygmi-2.2.7/pygmi.egg-info/SOURCES.txt +105 -0
  99. pygmi-2.2.7/pygmi.egg-info/dependency_links.txt +1 -0
  100. pygmi-2.2.7/pygmi.egg-info/entry_points.txt +3 -0
  101. pygmi-2.2.7/pygmi.egg-info/not-zip-safe +1 -0
  102. pygmi-2.2.7/pygmi.egg-info/requires.txt +7 -0
  103. pygmi-2.2.7/pygmi.egg-info/top_level.txt +1 -0
  104. pygmi-2.2.7/quickstart.py +35 -0
  105. pygmi-2.2.7/setup.cfg +8 -0
  106. pygmi-2.2.7/setup.py +80 -0
@@ -0,0 +1,1265 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Name: grvmag3d.py (part of PyGMI)
3
+ #
4
+ # Author: Patrick Cole
5
+ # E-Mail: pcole@geoscience.org.za
6
+ #
7
+ # Copyright: (c) 2013 Council for Geoscience
8
+ # Licence: GPL-3.0
9
+ #
10
+ # This file is part of PyGMI
11
+ #
12
+ # PyGMI is free software: you can redistribute it and/or modify
13
+ # it under the terms of the GNU General Public License as published by
14
+ # the Free Software Foundation, either version 3 of the License, or
15
+ # (at your option) any later version.
16
+ #
17
+ # PyGMI is distributed in the hope that it will be useful,
18
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ # GNU General Public License for more details.
21
+ #
22
+ # You should have received a copy of the GNU General Public License
23
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
24
+ # -----------------------------------------------------------------------------
25
+ """ Gravity and magnetic field calculations.
26
+ This uses the following algorithms:
27
+
28
+ References:
29
+ Singh, B., Guptasarma, D., 2001. New method for fast computation of gravity
30
+ and magnetic anomalies from arbitrary polyhedral. Geophysics 66, 521-526.
31
+
32
+ Blakely, R.J., 1996. Potential Theory in Gravity and Magnetic Applications,
33
+ 1st edn. Cambridge University Press, Cambridge, UK, 441 pp. 200-201
34
+ """
35
+
36
+ from __future__ import print_function
37
+
38
+ from PyQt4 import QtGui, QtCore
39
+ import scipy.interpolate as si
40
+ import numpy as np
41
+ import pylab as plt
42
+ import copy
43
+ import tempfile
44
+ from scipy.linalg import norm
45
+ from pygmi.pfmod.datatypes import LithModel
46
+ from numba import jit
47
+ from matplotlib import cm
48
+
49
+
50
+ class GravMag(object):
51
+ """This class holds the generic magnetic and gravity modelling routines
52
+
53
+ Routine that will calculate the final versions of the field. Other,
54
+ related code is here as well, such as the inversion routines.
55
+ """
56
+ def __init__(self, parent):
57
+
58
+ self.parent = parent
59
+ self.lmod1 = parent.lmod1
60
+ self.lmod2 = parent.lmod2
61
+ self.lmod = self.lmod1
62
+ self.showtext = parent.showtext
63
+ if hasattr(parent, 'pbars'):
64
+ self.pbars = parent.pbars
65
+ else:
66
+ self.pbars = None
67
+ self.oldlithindex = None
68
+ self.mfname = self.parent.modelfilename
69
+ self.tmpfiles = {}
70
+
71
+ self.actionregionaltest = QtGui.QPushButton(self.parent)
72
+ self.actioncalculate = QtGui.QPushButton(self.parent)
73
+ self.actioncalculate2 = QtGui.QPushButton(self.parent)
74
+ self.setupui()
75
+
76
+ def setupui(self):
77
+ """ Setup UI """
78
+ self.actionregionaltest.setText("Regional Test")
79
+ self.actioncalculate.setText("Calculate Gravity")
80
+ self.actioncalculate2.setText("Calculate Magnetics")
81
+ self.parent.toolbar.addWidget(self.actionregionaltest)
82
+ self.parent.toolbar.addSeparator()
83
+ self.parent.toolbar.addWidget(self.actioncalculate)
84
+ self.parent.toolbar.addWidget(self.actioncalculate2)
85
+ self.parent.toolbar.addSeparator()
86
+
87
+ self.actionregionaltest.clicked.connect(self.test_pattern)
88
+ self.actioncalculate.clicked.connect(self.calc_field)
89
+ self.actioncalculate2.clicked.connect(self.calc_field_new)
90
+
91
+ def calc_field_new(self):
92
+ """ Pre field-calculation routine """
93
+ self.lmod1 = self.parent.lmod1
94
+ self.lmod2 = self.parent.lmod2
95
+ self.lmod = self.lmod1
96
+ self.parent.pview.viewmagnetics = True
97
+ self.parent.profile.viewmagnetics = True
98
+
99
+ # Update the model from the view
100
+ indx = self.parent.tabwidget.currentIndex()
101
+ tlabel = self.parent.tabwidget.tabText(indx)
102
+
103
+ if tlabel == 'Layer Editor':
104
+ self.parent.layer.update_model()
105
+
106
+ if tlabel == 'Profile Editor':
107
+ self.parent.profile.update_model()
108
+
109
+ if tlabel == 'Custom Profile Editor':
110
+ self.parent.pview.update_model()
111
+
112
+ # now do the calculations
113
+ self.calc_field2(True, True)
114
+
115
+ if tlabel == 'Profile Editor':
116
+ self.parent.profile.update_plot()
117
+
118
+ if tlabel == 'Custom Profile Editor':
119
+ self.parent.pview.update_plot()
120
+
121
+ def calc_field(self):
122
+ """ Pre field-calculation routine """
123
+ # Update this
124
+ self.lmod1 = self.parent.lmod1
125
+ self.lmod2 = self.parent.lmod2
126
+ self.lmod = self.lmod1
127
+ self.parent.profile.viewmagnetics = False
128
+ self.parent.pview.viewmagnetics = False
129
+
130
+ # Update the model from the view
131
+ indx = self.parent.tabwidget.currentIndex()
132
+ tlabel = self.parent.tabwidget.tabText(indx)
133
+
134
+ if tlabel == 'Layer Editor':
135
+ self.parent.layer.update_model()
136
+
137
+ if tlabel == 'Profile Editor':
138
+ self.parent.profile.update_model()
139
+
140
+ if tlabel == 'Custom Profile Editor':
141
+ self.parent.pview.update_model()
142
+
143
+ # now do the calculations
144
+ self.calc_field2(True)
145
+
146
+ if tlabel == 'Profile Editor':
147
+ self.parent.profile.update_plot()
148
+
149
+ if tlabel == 'Custom Profile Editor':
150
+ self.parent.pview.update_plot()
151
+
152
+ def calc_field2(self, showreports=False, magcalc=False):
153
+ """ Calculate magnetic and gravity field """
154
+
155
+ calc_field(self.lmod, pbars=self.pbars, showtext=self.showtext,
156
+ parent=self.parent, showreports=showreports,
157
+ magcalc=magcalc)
158
+
159
+ def calc_regional(self):
160
+ """
161
+ Calculates a gravity and magnetic regional value based on a single
162
+ solid lithology model. This gets used in tab_param. The principle is
163
+ that the maximum value for a solid model with fixed extents and depth,
164
+ using the most COMMON lithology, would be the MAXIMUM AVERAGE value for
165
+ any model which we would do. Therefore the regional is simply:
166
+ REGIONAL = OBS GRAVITY MEAN - CALC GRAVITY MAX
167
+ This routine calculates the last term.
168
+ """
169
+
170
+ ltmp = list(self.lmod1.lith_list.keys())
171
+ ltmp.pop(ltmp.index('Background'))
172
+
173
+ text, okay = QtGui.QInputDialog.getItem(
174
+ self.parent, 'Regional Test',
175
+ 'Please choose the lithology to use:',
176
+ ltmp)
177
+
178
+ if not okay:
179
+ return
180
+
181
+ lmod1 = self.lmod1
182
+ self.lmod2 = LithModel()
183
+ # This line ensures that lmod2 is different to lmod1
184
+ # self.lmod2 = copy.copy(self.lmod2)
185
+ self.lmod2.lith_list.clear()
186
+
187
+ numlayers = lmod1.numz
188
+ layerthickness = lmod1.d_z
189
+
190
+ self.lmod2.update(lmod1.numx, lmod1.numy, numlayers, lmod1.xrange[0],
191
+ lmod1.yrange[1], lmod1.zrange[1], lmod1.dxy,
192
+ layerthickness, lmod1.mht, lmod1.ght)
193
+
194
+ self.lmod2.lith_index = self.lmod1.lith_index.copy()
195
+ self.lmod2.lith_index[self.lmod2.lith_index != -1] = 1
196
+
197
+ self.lmod2.lith_list['Background'] = GeoData(
198
+ self.parent, lmod1.numx, lmod1.numy, self.lmod2.numz, lmod1.dxy,
199
+ self.lmod2.d_z, lmod1.mht, lmod1.ght)
200
+
201
+ self.lmod2.lith_list['Regional'] = GeoData(
202
+ self.parent, lmod1.numx, lmod1.numy, self.lmod2.numz, lmod1.dxy,
203
+ self.lmod2.d_z, lmod1.mht, lmod1.ght)
204
+
205
+ lithn = self.lmod2.lith_list['Regional']
206
+ litho = self.lmod1.lith_list[text]
207
+ lithn.hintn = litho.hintn
208
+ lithn.finc = litho.finc
209
+ lithn.fdec = litho.fdec
210
+ lithn.zobsm = litho.zobsm
211
+ lithn.susc = litho.susc
212
+ lithn.mstrength = litho.mstrength
213
+ lithn.qratio = litho.qratio
214
+ lithn.minc = litho.minc
215
+ lithn.mdec = litho.mdec
216
+ lithn.density = litho.density
217
+ lithn.bdensity = litho.bdensity
218
+ lithn.zobsg = litho.zobsg
219
+ lithn.lith_index = 1
220
+
221
+ self.lmod = self.lmod2
222
+ self.calc_field2(False, False)
223
+ self.calc_field2(False, True)
224
+ self.lmod = self.lmod1
225
+
226
+ def grd_to_lith(self, curgrid):
227
+ """ Assign the DTM to the lithology model """
228
+ d_x = curgrid.xdim
229
+ d_y = curgrid.ydim
230
+ utlx = curgrid.tlx
231
+ utly = curgrid.tly
232
+ gcols = curgrid.cols
233
+ grows = curgrid.rows
234
+
235
+ gxmin = utlx
236
+ gymax = utly
237
+
238
+ ndata = np.zeros([self.lmod.numy, self.lmod.numx])
239
+
240
+ for i in range(self.lmod.numx):
241
+ for j in range(self.lmod.numy):
242
+ xcrd = self.lmod.xrange[0]+(i+.5)*self.lmod.dxy
243
+ ycrd = self.lmod.yrange[1]-(j+.5)*self.lmod.dxy
244
+ xcrd2 = int((xcrd-gxmin)/d_x)
245
+ ycrd2 = int((gymax-ycrd)/d_y)
246
+ if (ycrd2 >= 0 and xcrd2 >= 0 and ycrd2 < grows and
247
+ xcrd2 < gcols):
248
+ ndata[j, i] = curgrid.data.data[ycrd2, xcrd2]
249
+
250
+ return ndata
251
+
252
+ def test_pattern(self):
253
+ """ Displays a test pattern of the data - an indication of the edge of
254
+ model field decay. It gives an idea about how reliable the calculated
255
+ field on the edge of the model is. """
256
+ self.lmod1 = self.parent.lmod1
257
+ self.lmod2 = self.parent.lmod2
258
+ self.lmod = self.lmod1
259
+
260
+ self.calc_regional()
261
+
262
+ magtmp = self.lmod2.griddata['Calculated Magnetics'].data
263
+ grvtmp = self.lmod2.griddata['Calculated Gravity'].data
264
+
265
+ regplt = plt.figure()
266
+ axes = plt.subplot(1, 2, 1)
267
+ etmp = dat_extent(self.lmod2.griddata['Calculated Magnetics'], axes)
268
+ plt.title('Magnetic Data')
269
+ ims = plt.imshow(magtmp, extent=etmp)
270
+ mmin = magtmp.mean()-2*magtmp.std()
271
+ mmax = magtmp.mean()+2*magtmp.std()
272
+ mint = (magtmp.std()*4)/10.
273
+ csrange = np.arange(mmin, mmax, mint)
274
+ cns = plt.contour(magtmp, levels=csrange, colors='b', extent=etmp)
275
+ plt.clabel(cns, inline=1, fontsize=10)
276
+ cbar = plt.colorbar(ims, orientation='horizontal')
277
+ cbar.set_label('nT')
278
+
279
+ axes = plt.subplot(1, 2, 2)
280
+ etmp = dat_extent(self.lmod2.griddata['Calculated Gravity'], axes)
281
+ plt.title('Gravity Data')
282
+ ims = plt.imshow(grvtmp, extent=etmp)
283
+ mmin = grvtmp.mean()-2*grvtmp.std()
284
+ mmax = grvtmp.mean()+2*grvtmp.std()
285
+ mint = (grvtmp.std()*4)/10.
286
+ csrange = np.arange(mmin, mmax, mint)
287
+ cns = plt.contour(grvtmp, levels=csrange, colors='y', extent=etmp)
288
+
289
+ plt.clabel(cns, inline=1, fontsize=10)
290
+ cbar = plt.colorbar(ims, orientation='horizontal')
291
+ cbar.set_label('mgal')
292
+
293
+ regplt.show()
294
+
295
+ def update_graph(self, grvval, magval, modind):
296
+ """ Updates the graph """
297
+ indx = self.parent.tabwidget.currentIndex()
298
+ tlabel = self.parent.tabwidget.tabText(indx)
299
+
300
+ self.lmod.lith_index = modind.copy()
301
+ self.lmod.griddata['Calculated Gravity'].data = grvval.T.copy()
302
+ self.lmod.griddata['Calculated Magnetics'].data = magval.T.copy()
303
+
304
+ if tlabel == 'Layer Editor':
305
+ self.parent.layer.combo()
306
+ if tlabel == 'Profile Editor':
307
+ self.parent.profile.update_plot(slide=True)
308
+
309
+
310
+ class GeoData(object):
311
+ """ Data layer class:
312
+ This class defines each geological type and calculates the field
313
+ for one cube from the standard definitions.
314
+
315
+ The is a class which contains the geophysical information for a single
316
+ lithology. This includes the final calculated field for that lithology
317
+ only.
318
+ """
319
+ def __init__(self, parent, ncols=10, nrows=10, numz=10, dxy=10.,
320
+ d_z=10., mht=80., ght=0.):
321
+ self.hintn = 30000.
322
+ self.susc = 0.01
323
+ self.mstrength = 0.
324
+ self.finc = -63.
325
+ self.fdec = -17.
326
+ self.minc = -63.
327
+ self.mdec = -17.
328
+ self.theta = 90.
329
+ self.bdensity = 2.67
330
+ self.density = 2.85
331
+ self.qratio = 0.0
332
+ self.lith_index = 0
333
+ self.parent = parent
334
+ if hasattr(parent, 'pbars'):
335
+ self.pbars = parent.pbars
336
+ else:
337
+ self.pbars = None
338
+
339
+ if hasattr(parent, 'showtext'):
340
+ self.showtext = parent.showtext
341
+ else:
342
+ self.showtext = print
343
+
344
+ # ncols and nrows are the smaller dimension of the original grid.
345
+ # numx, numy, numz are the dimensions of the larger grid to be used as a
346
+ # template.
347
+
348
+ self.modified = True
349
+ self.g_cols = None
350
+ self.g_rows = None
351
+ self.g_dxy = None
352
+ self.numz = None
353
+ self.dxy = None
354
+ self.d_z = None
355
+ self.zobsm = None
356
+ self.zobsg = None
357
+
358
+ self.mlayers = None
359
+ self.glayers = None
360
+
361
+ self.x12 = None
362
+ self.y12 = None
363
+ self.z12 = None
364
+
365
+ self.set_xyz(ncols, nrows, numz, dxy, mht, ght, d_z)
366
+
367
+ def calc_origin(self):
368
+ """ Calculate the field values for the lithologies"""
369
+
370
+ if self.modified is True:
371
+ numx = self.g_cols*self.g_dxy
372
+ numy = self.g_rows*self.g_dxy
373
+
374
+ # The 2 lines below ensure that the profile goes over the center of the grid
375
+ # cell
376
+ xdist = np.arange(self.g_dxy/2, numx+self.g_dxy/2, self.g_dxy,
377
+ dtype=float)
378
+ ydist = np.arange(numy-self.g_dxy/2, -self.g_dxy/2, -self.g_dxy,
379
+ dtype=float)
380
+
381
+ # self.showtext(' Calculate magnetic origin field')
382
+ # self.mboxmain(xdist, ydist, self.zobsm)
383
+ self.showtext(' Calculate gravity origin field')
384
+ self.gboxmain(xdist, ydist, self.zobsg)
385
+
386
+ self.modified = False
387
+ else:
388
+ pass
389
+ # self.pbars.incrmain(2)
390
+
391
+ def calc_origin2(self):
392
+ """ Calculate the field values for the lithologies"""
393
+
394
+ if self.modified is True:
395
+ numx = self.g_cols*self.g_dxy
396
+ numy = self.g_rows*self.g_dxy
397
+
398
+ # The 2 lines below ensure that the profile goes over the center of the grid
399
+ # cell
400
+ xdist = np.arange(self.g_dxy/2, numx+self.g_dxy/2, self.g_dxy,
401
+ dtype=float)
402
+ ydist = np.arange(numy-self.g_dxy/2, -self.g_dxy/2, -self.g_dxy,
403
+ dtype=float)
404
+
405
+ self.showtext(' Calculate magnetic origin field')
406
+ self.gmmain(xdist, ydist)
407
+
408
+ self.modified = False
409
+ else:
410
+ pass
411
+ # self.pbars.incrmain(2)
412
+
413
+ def netmagn(self):
414
+ """ Calculate the net magnetization """
415
+ theta = 0.
416
+ fcx, fcy, fcz = dircos(self.finc, self.fdec, theta)
417
+ unith = np.array([fcx, fcy, fcz])
418
+ hintn = self.hintn * 10**-9 # in Tesla
419
+ mu0 = 4*np.pi*10**-7
420
+ hstrength = self.susc*hintn/mu0 # Induced magnetization, needs susc.
421
+ ind_magn = hstrength*unith
422
+
423
+ # B is Induced Field (Tesla)
424
+ # M is Magnetization (A/m)
425
+ # H is Magnetic Field (A/m)
426
+ # k is Susceptibility and is M/H
427
+ # ` B = mu0(H+M)
428
+ # Q = Jr/Ji = mstrength/hstrength = Jr/kH
429
+
430
+ mcx, mcy, mcz = dircos(self.minc, self.mdec, theta)
431
+ unitm = np.array([mcx, mcy, mcz])
432
+ rem_magn = self.mstrength*unitm # Remnant magnetization
433
+ net_magn = rem_magn+ind_magn # Net magnetization
434
+ netmagscalar = np.sqrt((net_magn**2).sum())
435
+ return netmagscalar
436
+
437
+ def rho(self):
438
+ """ Returns the density contrast """
439
+ return self.density - self.bdensity
440
+
441
+ def set_xyz(self, ncols, nrows, numz, g_dxy, mht, ght, d_z, dxy=None,
442
+ modified=True):
443
+ """ Sets/updates xyz parameters again """
444
+ self.modified = modified
445
+ self.g_cols = ncols*2+1
446
+ self.g_rows = nrows*2+1
447
+ self.numz = numz
448
+ self.g_dxy = g_dxy
449
+ self.d_z = d_z
450
+ self.zobsm = -mht
451
+ self.zobsg = -ght
452
+
453
+ if dxy is None:
454
+ self.dxy = g_dxy # This must be a multiple of g_dxy or equal to it
455
+ else:
456
+ self.dxy = dxy # This must be a multiple of g_dxy or equal to it.
457
+
458
+ self.set_xyz12()
459
+
460
+ def set_xyz12(self):
461
+ """ Set x12, y12, z12. This is the limits of the cubes for the model"""
462
+
463
+ numx = self.g_cols*self.g_dxy
464
+ numy = self.g_rows*self.g_dxy
465
+ numz = self.numz*self.d_z
466
+ dxy = self.dxy
467
+ d_z = self.d_z
468
+
469
+ self.x12 = np.array([numx/2-dxy/2, numx/2+dxy/2])
470
+ self.y12 = np.array([numy/2-dxy/2, numy/2+dxy/2])
471
+ self.z12 = np.arange(-numz, numz+d_z, d_z)
472
+
473
+ def gmmain(self, xobs, yobs):
474
+ """ Algorithm for simultaneous computation of gravity and magnetic
475
+ fields is based on the formulation published in GEOPHYSICS v. 66,
476
+ 521-526,2001. by Bijendra Singh and D. Guptasarma """
477
+ if self.pbars is not None:
478
+ piter = self.pbars.iter
479
+ else:
480
+ piter = iter
481
+
482
+ x1 = float(self.x12[0])
483
+ x2 = float(self.x12[1])
484
+ y1 = float(self.y12[0])
485
+ y2 = float(self.y12[1])
486
+ # z1 = float(self.z12[0])
487
+ # z2 = float(self.z12[1])
488
+ z1 = 0.0
489
+ z2 = self.d_z
490
+
491
+ # ncor = 8
492
+ corner = np.array([[x1, y1, z1],
493
+ [x1, y2, z1],
494
+ [x2, y2, z1],
495
+ [x2, y1, z1],
496
+ [x1, y1, z2],
497
+ [x1, y2, z2],
498
+ [x2, y2, z2],
499
+ [x2, y1, z2]])
500
+
501
+ nf = 6
502
+ face = np.array([[0, 1, 2, 3],
503
+ [4, 7, 6, 5],
504
+ [1, 5, 6, 2],
505
+ [4, 0, 3, 7],
506
+ [3, 2, 6, 7],
507
+ [4, 5, 1, 0]])
508
+
509
+ # nedges = sum(face(1:nf,1))
510
+ nedges = 4*nf
511
+ edge = np.zeros([nedges, 8])
512
+ # get edge lengths
513
+ for f in range(nf):
514
+ indx = face[f].tolist() + [face[f, 0]]
515
+ for t in range(4):
516
+ # edgeno = sum(face(1:f-1,1))+t
517
+ edgeno = f*4+t
518
+ ends = indx[t:t+2]
519
+ p1 = corner[ends[0]]
520
+ p2 = corner[ends[1]]
521
+ V = p2-p1
522
+ L = norm(V)
523
+ edge[edgeno, 0:3] = V
524
+ edge[edgeno, 3] = L
525
+ edge[edgeno, 6:8] = ends
526
+
527
+ un = np.zeros([nf, 3])
528
+ # get face normals
529
+ for t in range(nf):
530
+ ss = np.zeros([1, 3])
531
+ for t1 in range(2):
532
+ v1 = corner[face[t, t1+2]]-corner[face[t, 0]]
533
+ v2 = corner[face[t, t1+1]]-corner[face[t, 0]]
534
+ ss = ss+np.cross(v2, v1)
535
+ un[t, :] = ss/norm(ss)
536
+
537
+ # Define the survey grid
538
+ X, Y = np.meshgrid(xobs, yobs)
539
+
540
+ npro, nstn = X.shape
541
+ # Initialise
542
+
543
+ # Grav stuff
544
+ # Gc = 6.6732e-3 # Universal gravitational constant
545
+ # Gx = np.zeros(X.shape)
546
+ # Gy = Gx.copy()
547
+ # Gz = Gx.copy()
548
+
549
+ # Mag stuff
550
+ cx, cy, cz = dircos(self.finc, self.fdec, 90.0)
551
+ uh = np.array([cx, cy, cz])
552
+ H = self.hintn*uh # The ambient magnetic field (nTesla)
553
+ ind_magn = self.susc*H/(4*np.pi) # Induced magnetization
554
+
555
+ mcx, mcy, mcz = dircos(self.minc, self.mdec, 90.0)
556
+ um = np.array([mcx, mcy, mcz])
557
+ rem_magn = (400*np.pi*self.mstrength)*um # Remanent magnetization
558
+
559
+ net_magn = rem_magn+ind_magn # Net magnetization
560
+ Pd = np.transpose(np.dot(un, net_magn.T)) # Pole densities
561
+
562
+ Hx = np.zeros(X.shape)
563
+ Hy = Hx.copy()
564
+ Hz = Hx.copy()
565
+
566
+ # For each observation point do the following.
567
+ # For each face find the solid angle.
568
+ # For each side find p,q,r and add p,q,r of sides to get P,Q,R for the
569
+ # face.
570
+ # find hx,hy,hz.
571
+ # find gx,gy,gz.
572
+ # Add the components from all the faces to get Hx,Hy,Hz and Gx,Gy,Gz.
573
+
574
+
575
+ # face = face.tolist()
576
+ # un = un.tolist()
577
+ # gval = []
578
+ mval = []
579
+ newdepth = self.z12+abs(self.zobsm)
580
+
581
+ for depth in piter(newdepth):
582
+ if depth == 0.0:
583
+ cor = (corner + [0., 0., depth+self.d_z/10000.])
584
+ elif depth == -self.d_z:
585
+ cor = (corner + [0., 0., depth-self.d_z/10000.])
586
+ else:
587
+ cor = (corner + [0., 0., depth])
588
+
589
+ if depth in newdepth:
590
+ # Gx = np.zeros(X.shape)
591
+ # Gy = Gx.copy()
592
+ # Gz = Gx.copy()
593
+ Hx = np.zeros(X.shape)
594
+ Hy = Hx.copy()
595
+ Hz = Hx.copy()
596
+
597
+ indx = np.array([0, 1, 2, 3, 0, 1])
598
+ crs = np.zeros([4, 3])
599
+ p1 = np.zeros(3)
600
+ p2 = np.zeros(3)
601
+ p3 = np.zeros(3)
602
+ mgval = np.zeros([3, npro, nstn])
603
+
604
+ mgval = gm3d(npro, nstn, X, Y, edge, cor, face, # Gx, Gy, Gz,
605
+ Hx, Hy, Hz, Pd, un, indx, crs, p1, p2, p3,
606
+ mgval)
607
+
608
+ Hx = mgval[0]
609
+ Hy = mgval[1]
610
+ Hz = mgval[2]
611
+ # Gx = mgval[3] * Gc
612
+ # Gy = mgval[4] * Gc
613
+ # Gz = mgval[5] * Gc
614
+
615
+ # Htot = np.sqrt((Hx+H[0])**2 + (Hy+H[1])**2 + (Hz+H[2])**2)
616
+ # dt = Htot-self.hintn
617
+ dta = Hx*cx + Hy*cy + Hz*cz
618
+ else:
619
+ # Gz = np.zeros(X.shape)
620
+ dta = np.zeros(X.shape)
621
+
622
+ # gval.append(np.copy(Gz.T))
623
+ mval.append(np.copy(dta.T))
624
+
625
+ # self.glayers = np.array(gval)
626
+ self.mlayers = np.array(mval)
627
+
628
+ def gboxmain(self, xobs, yobs, zobs):
629
+ """ Gbox routine by Blakely
630
+ Note: xobs, yobs and zobs must be floats or there will be problems
631
+ later.
632
+
633
+ Subroutine GBOX computes the vertical attraction of a
634
+ rectangular prism. Sides of prism are parallel to x,y,z axes,
635
+ and z axis is vertical down.
636
+
637
+ Input parameters:
638
+ Observation point is (x0,y0,z0). The prism extends from x1
639
+ to x2, from y1 to y2, and from z1 to z2 in the x, y, and z
640
+ directions, respectively. Density of prism is rho. All
641
+ distance parameters in units of m;
642
+
643
+ Output parameters:
644
+ Vertical attraction of gravity, g, in mGal/rho.
645
+ Must still be multiplied by rho outside routine.
646
+ Done this way for speed. """
647
+
648
+ glayers = []
649
+ if self.pbars is not None:
650
+ piter = self.pbars.iter
651
+ else:
652
+ piter = iter
653
+ z1122 = self.z12.copy()
654
+ x_1 = float(self.x12[0])
655
+ y_1 = float(self.y12[0])
656
+ x_2 = float(self.x12[1])
657
+ y_2 = float(self.y12[1])
658
+ z_0 = float(zobs)
659
+ numx = int(self.g_cols)
660
+ numy = int(self.g_rows)
661
+
662
+ if zobs == 0:
663
+ zobs = -0.01
664
+
665
+ for i in piter(z1122[:-1]):
666
+ z12 = np.array([i, i+self.d_z])
667
+
668
+ z_1 = float(z12[0])
669
+ z_2 = float(z12[1])
670
+ gval = np.zeros([self.g_cols, self.g_rows])
671
+
672
+ gval = gboxmain2(gval, xobs, yobs, numx, numy, z_0, x_1, y_1, z_1,
673
+ x_2, y_2, z_2, np.ones(2), np.ones(2), np.ones(2),
674
+ np.array([-1, 1]))
675
+
676
+ gval *= 6.6732e-3
677
+ glayers.append(gval)
678
+ self.glayers = np.array(glayers)
679
+
680
+
681
+ def save_layer(mlist):
682
+ """ Routine saves the mlayer and glayer to a file """
683
+ outfile = tempfile.TemporaryFile()
684
+
685
+ outdict = {}
686
+
687
+ outdict['mlayers'] = mlist[1].mlayers
688
+ outdict['glayers'] = mlist[1].glayers
689
+
690
+ np.savez(outfile, **outdict)
691
+ outfile.seek(0)
692
+
693
+ mlist[1].mlayers = None
694
+ mlist[1].glayers = None
695
+
696
+ return outfile
697
+
698
+
699
+ def gridmatch(lmod, ctxt, rtxt):
700
+ """ Matches the rows and columns of the second grid to the first
701
+ grid """
702
+ rgrv = lmod.griddata[rtxt]
703
+ cgrv = lmod.griddata[ctxt]
704
+ x = np.arange(rgrv.tlx, rgrv.tlx+rgrv.cols*rgrv.xdim,
705
+ rgrv.xdim)+0.5*rgrv.xdim
706
+ y = np.arange(rgrv.tly-rgrv.rows*rgrv.ydim, rgrv.tly,
707
+ rgrv.xdim)+0.5*rgrv.ydim
708
+ x_2, y_2 = np.meshgrid(x, y)
709
+ z_2 = rgrv.data
710
+ x_i = np.arange(cgrv.cols)*cgrv.xdim + cgrv.tlx + 0.5*cgrv.xdim
711
+ y_i = np.arange(cgrv.rows)*cgrv.ydim + cgrv.tly - \
712
+ cgrv.rows*cgrv.ydim + 0.5*cgrv.ydim
713
+ xi2, yi2 = np.meshgrid(x_i, y_i)
714
+
715
+ zfin = si.griddata((x_2.flatten(), y_2.flatten()), z_2.flatten(),
716
+ (xi2.flatten(), yi2.flatten()))
717
+ zfin = np.ma.masked_invalid(zfin)
718
+ zfin.shape = cgrv.data.shape
719
+
720
+ return zfin
721
+
722
+
723
+ def calc_field(lmod, pbars=None, showtext=None, parent=None, showreports=False,
724
+ magcalc=False):
725
+ """ Calculate magnetic and gravity field
726
+
727
+ This function calculates the magnetic and gravity field. It has two
728
+ different modes of operation, by using the magcalc switch. If magcalc=True
729
+ then magnetic fields are calculated, otherwize only
730
+ gravity is calculated.
731
+
732
+ Parameters
733
+ ----------
734
+ lmod : LithModel
735
+ PyGMI lithological model
736
+ pbars : module
737
+ progress bar routine if available. (internal use)
738
+ showtext : module
739
+ showtext routine if available. (internal use)
740
+ parent : parent
741
+ parent function. (internal use)
742
+ showreports : bool
743
+ show extra reports
744
+ magcalc : bool
745
+ if true, calculates magnetic data, otherwize only gravity.
746
+
747
+ Returns
748
+ -------
749
+ lmod.griddata : dictionary
750
+ dictionary of items of type Data.
751
+ """
752
+
753
+ if showtext is None:
754
+ showtext = print
755
+ if pbars is not None:
756
+ pbars.resetall(mmax=2*(len(lmod.lith_list)-1)+1)
757
+ piter = pbars.iter
758
+ else:
759
+ piter = iter
760
+ if np.max(lmod.lith_index) == -1:
761
+ showtext('Error: Create a model first')
762
+ return
763
+
764
+ # Init some variables for convenience
765
+ lmod.update_lithlist()
766
+
767
+ numx = int(lmod.numx)
768
+ numy = int(lmod.numy)
769
+ numz = int(lmod.numz)
770
+ tmpfiles = {}
771
+
772
+ # This forces a full recalc every time.
773
+ lmod.clith_index[:] = 0
774
+ lmod.cmagcalc = magcalc
775
+
776
+ # if lmod.cmagcalc is not magcalc:
777
+ # lmod.clith_index[:] = 0
778
+ # lmod.cmagcalc = magcalc
779
+
780
+ if lmod.clith_index.max() == 0 and magcalc:
781
+ lmod.griddata['Calculated Magnetics'].data[:] = 0
782
+ elif lmod.clith_index.max() == 0:
783
+ lmod.griddata['Calculated Gravity'].data[:] = 0
784
+
785
+ # model index
786
+ modind = lmod.lith_index.copy()
787
+ modindcheck = lmod.lith_index.copy()
788
+ cmodind = lmod.clith_index.copy()
789
+ tmp = (modind == cmodind)
790
+ modind[tmp] = -1
791
+ cmodind[tmp] = -1
792
+ modind[modind == 0] = -1
793
+ cmodind[cmodind == 0] = -1
794
+ modindcheck[modind == 0] = -1
795
+
796
+ if (abs(np.sum(modind == -1)) == modind.size and
797
+ abs(np.sum(cmodind == -1)) == cmodind.size):
798
+ showtext('No changes to model!')
799
+ return
800
+
801
+ for mlist in lmod.lith_list.items():
802
+ # if 'Background' != mlist[0] and mlist[1].modified is True:
803
+ mijk = mlist[1].lith_index
804
+ if mijk not in modind and mijk not in cmodind:
805
+ continue
806
+ if 'Background' != mlist[0]: # and 'Penge' in mlist[0]:
807
+ mlist[1].modified = True
808
+ showtext(mlist[0]+':')
809
+ if parent is not None:
810
+ mlist[1].parent = parent
811
+ mlist[1].pbars = parent.pbars
812
+ mlist[1].showtext = parent.showtext
813
+ if magcalc:
814
+ mlist[1].calc_origin2()
815
+ else:
816
+ mlist[1].calc_origin()
817
+ tmpfiles[mlist[0]] = save_layer(mlist)
818
+
819
+ if showreports is True:
820
+ showtext('Summing data')
821
+
822
+ QtCore.QCoreApplication.processEvents()
823
+ # get height corrections
824
+ tmp = np.copy(lmod.lith_index)
825
+ tmp[tmp > -1] = 0
826
+ hcor = np.abs(tmp.sum(2))
827
+
828
+ # Get mlayers and glayers with correct rho and netmagn
829
+
830
+ if pbars is not None:
831
+ pbars.resetsub(maximum=(len(lmod.lith_list)-1))
832
+ piter = pbars.iter
833
+ else:
834
+ piter = iter
835
+
836
+ magval = np.zeros([numx, numy])
837
+ grvval = np.zeros([numx, numy])
838
+ mtmp = magval.shape
839
+ magval = magval.flatten()
840
+ grvval = grvval.flatten()
841
+ hcorflat = numz-hcor.flatten()
842
+ aaa = np.reshape(np.mgrid[0:mtmp[0], 0:mtmp[1]], [2, numx*numy])
843
+
844
+ # ttt = PTime()
845
+ mgval = np.zeros([2, magval.size])
846
+
847
+ for mlist in piter(lmod.lith_list.items()):
848
+ if 'Background' == mlist[0]:
849
+ continue
850
+ mijk = mlist[1].lith_index
851
+ if mijk not in modind and mijk not in cmodind:
852
+ continue
853
+ tmpfiles[mlist[0]].seek(0)
854
+ mfile = np.load(tmpfiles[mlist[0]])
855
+ if magcalc:
856
+ mlayers = mfile['mlayers']
857
+ elif mfile['mlayers'].size > 1:
858
+ mlayers = mfile['mlayers']*mlist[1].netmagn()
859
+ else:
860
+ mlayers = np.zeros_like(mfile['glayers'])
861
+
862
+ if not magcalc:
863
+ glayers = mfile['glayers']*mlist[1].rho()
864
+ elif mfile['glayers'].size > 1:
865
+ glayers = mfile['glayers']*mlist[1].rho()
866
+ else:
867
+ glayers = np.zeros_like(mfile['mlayers'])
868
+
869
+
870
+ # glayers = mfile['glayers']*mlist[1].rho()
871
+
872
+ showtext('Summing '+mlist[0]+' (PyGMI may become non-responsive' +
873
+ ' during this calculation)')
874
+
875
+ if abs(np.sum(modind == -1)) < modind.size and mijk in modind:
876
+ QtGui.QApplication.processEvents()
877
+ i, j, k = np.nonzero(modind == mijk)
878
+ iuni = np.array(np.unique(i), dtype=np.int32)
879
+ juni = np.array(np.unique(j), dtype=np.int32)
880
+ kuni = np.array(np.unique(k), dtype=np.int32)
881
+
882
+ for k in kuni:
883
+ baba = calc_fieldb(k, mgval, numx, numy, modind, aaa[0],
884
+ aaa[1], mlayers, glayers, hcorflat, mijk,
885
+ juni, iuni)
886
+ magval += baba[0]
887
+ grvval += baba[1]
888
+
889
+ if abs(np.sum(cmodind == -1)) < cmodind.size and mijk in cmodind:
890
+ print('subtracting')
891
+ QtGui.QApplication.processEvents()
892
+ i, j, k = np.nonzero(cmodind == mijk)
893
+ iuni = np.array(np.unique(i), dtype=np.int32)
894
+ juni = np.array(np.unique(j), dtype=np.int32)
895
+ kuni = np.array(np.unique(k), dtype=np.int32)
896
+
897
+ for k in kuni:
898
+ baba = calc_fieldb(k, mgval, numx, numy, modind, aaa[0],
899
+ aaa[1], mlayers, glayers, hcorflat, mijk,
900
+ juni, iuni)
901
+ magval += baba[0]
902
+ grvval += baba[1]
903
+
904
+ showtext('Done')
905
+
906
+ if pbars is not None:
907
+ pbars.incrmain()
908
+ QtGui.QApplication.processEvents()
909
+
910
+ magval.resize(mtmp)
911
+ grvval.resize(mtmp)
912
+ magval = magval.T
913
+ grvval = grvval.T
914
+ magval = magval[::-1]
915
+ grvval = grvval[::-1]
916
+
917
+ # magval += lmod.griddata['Calculated Magnetics'].data
918
+ # grvval += lmod.griddata['Calculated Gravity'].data
919
+
920
+ # Update variables
921
+ lmod.griddata['Calculated Magnetics'].data += magval
922
+ lmod.griddata['Calculated Gravity'].data += grvval
923
+
924
+ # This addoldcalc has has flaws w.r.t. regional if you change the regional
925
+ if 'Gravity Regional' in lmod.griddata and lmod.clith_index.max() == 0:
926
+ zfin = gridmatch(lmod, 'Calculated Gravity', 'Gravity Regional')
927
+ lmod.griddata['Calculated Gravity'].data += zfin
928
+
929
+ if lmod.lith_index.max() <= 0:
930
+ lmod.griddata['Calculated Magnetics'].data *= 0.
931
+ lmod.griddata['Calculated Gravity'].data *= 0.
932
+
933
+ if 'Magnetic Dataset' in lmod.griddata:
934
+ ztmp = gridmatch(lmod, 'Magnetic Dataset', 'Calculated Magnetics')
935
+ lmod.griddata['Magnetic Residual'] = copy.deepcopy(
936
+ lmod.griddata['Magnetic Dataset'])
937
+ lmod.griddata['Magnetic Residual'].data = (
938
+ lmod.griddata['Magnetic Dataset'].data - ztmp)
939
+ lmod.griddata['Magnetic Residual'].dataid = 'Magnetic Residual'
940
+
941
+ if 'Gravity Dataset' in lmod.griddata:
942
+ ztmp = gridmatch(lmod, 'Gravity Dataset', 'Calculated Gravity')
943
+ lmod.griddata['Gravity Residual'] = copy.deepcopy(
944
+ lmod.griddata['Gravity Dataset'])
945
+ lmod.griddata['Gravity Residual'].data = (
946
+ lmod.griddata['Gravity Dataset'].data - ztmp - lmod.gregional)
947
+ lmod.griddata['Gravity Residual'].dataid = 'Gravity Residual'
948
+
949
+ if parent is not None:
950
+ parent.outdata['Raster'] = list(lmod.griddata.values())
951
+ showtext('Calculation Finished')
952
+ if pbars is not None:
953
+ pbars.maxall()
954
+
955
+ lmod.clith_index = lmod.lith_index.copy()
956
+
957
+ return lmod.griddata
958
+
959
+
960
+ #@jit("f8[:,:](i4, f8[:,:], i4, i4, i4[:,:,:], i4[:], i4[:], " +
961
+ # "f8[:,:,:], f8[:,:,:], i4[:], i4, i4[:], i4[:])", nopython=True)
962
+ @jit(nopython=True)
963
+ def calc_fieldb(k, mgval, numx, numy, modind, aaa0, aaa1, mlayers,
964
+ glayers, hcorflat, mijk, jj, ii):
965
+ """ Calculate magnetic and gravity field """
966
+
967
+ b = numx*numy
968
+ for i in range(2):
969
+ for j in range(b):
970
+ mgval[i, j] = 0.
971
+
972
+ for i in ii:
973
+ xoff = numx-i
974
+ for j in jj:
975
+ yoff = numy-j
976
+ if (modind[i, j, k] != mijk):
977
+ continue
978
+ for ijk in range(b):
979
+ xoff2 = xoff + aaa0[ijk]
980
+ yoff2 = aaa1[ijk]+yoff
981
+ hcor2 = hcorflat[ijk]+k
982
+ mgval[0, ijk] += mlayers[hcor2, xoff2, yoff2]
983
+ mgval[1, ijk] += glayers[hcor2, xoff2, yoff2]
984
+
985
+ return mgval
986
+
987
+
988
+ def quick_model(numx=50, numy=50, numz=50, dxy=1000, d_z=100,
989
+ tlx=0, tly=0, tlz=0, mht=100, ght=0, finc=-67, fdec=-17,
990
+ inputliths=['Generic'], susc=[0.01], dens=[3.0],
991
+ minc=None, mdec=None, mstrength=None):
992
+ """ Create a quick model """
993
+
994
+ lmod = LithModel()
995
+ lmod.update(numx, numy, numz, tlx, tly, tlz, dxy, d_z, mht, ght)
996
+
997
+ lmod.lith_list['Background'] = GeoData(None, numx, numy, numz, dxy, d_z,
998
+ mht, ght)
999
+ lmod.lith_list['Background'].susc = 0
1000
+ lmod.lith_list['Background'].density = 2.67
1001
+ lmod.lith_list['Background'].finc = finc
1002
+ lmod.lith_list['Background'].fdec = fdec
1003
+ lmod.lith_list['Background'].minc = finc
1004
+ lmod.lith_list['Background'].mdec = fdec
1005
+
1006
+ j = 0
1007
+ if len(inputliths) == 1:
1008
+ clrtmp = np.array([0])
1009
+ else:
1010
+ clrtmp = np.arange(len(inputliths))/(len(inputliths)-1)
1011
+ clrtmp = cm.jet(clrtmp)[:, :-1]
1012
+ clrtmp *= 255
1013
+ clrtmp = clrtmp.astype(int)
1014
+
1015
+ for i in inputliths:
1016
+ j += 1
1017
+ lmod.mlut[j] = clrtmp[j-1]
1018
+ lmod.lith_list[i] = GeoData(None, numx, numy, numz, dxy, d_z, mht, ght)
1019
+
1020
+ lmod.lith_list[i].susc = susc[j-1]
1021
+ lmod.lith_list[i].density = dens[j-1]
1022
+ lmod.lith_list[i].lith_index = j
1023
+ lmod.lith_list[i].finc = finc
1024
+ lmod.lith_list[i].fdec = fdec
1025
+ if mstrength is not None:
1026
+ lmod.lith_list[i].minc = minc[j-1]
1027
+ lmod.lith_list[i].mdec = mdec[j-1]
1028
+ lmod.lith_list[i].mstrength = mstrength[j-1]
1029
+
1030
+ return lmod
1031
+
1032
+
1033
+ #@jit(float64[:,:](float64[:,:], float64[:], float64[:], int32, int32, float64,
1034
+ # float64, float64, float64, float64, float64, float64,
1035
+ # float64[:], float64[:], float64[:], int32[:]), nopython=True)
1036
+ @jit(nopython=True)
1037
+ def gboxmain2(gval, xobs, yobs, numx, numy, z_0, x_1, y_1, z_1, x_2, y_2, z_2,
1038
+ x, y, z, isign):
1039
+ """ Gbox routine by Blakely
1040
+ Note: xobs, yobs and zobs must be floats or there will be problems
1041
+ later.
1042
+
1043
+ Subroutine GBOX computes the vertical attraction of a
1044
+ rectangular prism. Sides of prism are parallel to x,y,z axes,
1045
+ and z axis is vertical down.
1046
+
1047
+ Input parameters:
1048
+ Observation point is (x0,y0,z0). The prism extends from x1
1049
+ to x2, from y1 to y2, and from z1 to z2 in the x, y, and z
1050
+ directions, respectively. Density of prism is rho. All
1051
+ distance parameters in units of m;
1052
+
1053
+ Output parameters:
1054
+ Vertical attraction of gravity, g, in mGal/rho.
1055
+ Must still be multiplied by rho outside routine.
1056
+ Done this way for speed. """
1057
+
1058
+ z[0] = z_0-z_1
1059
+ z[1] = z_0-z_2
1060
+
1061
+ for ii in range(numx):
1062
+ x[0] = xobs[ii]-x_1
1063
+ x[1] = xobs[ii]-x_2
1064
+ for jj in range(numy):
1065
+ y[0] = yobs[jj]-y_1
1066
+ y[1] = yobs[jj]-y_2
1067
+ sumi = 0.
1068
+ for i in range(2):
1069
+ for j in range(2):
1070
+ for k in range(2):
1071
+ rijk = np.sqrt(x[i]*x[i]+y[j]*y[j]+z[k]*z[k])
1072
+ ijk = isign[i]*isign[j]*isign[k]
1073
+ arg1 = np.arctan2(x[i]*y[j], z[k]*rijk)
1074
+
1075
+ if arg1 < 0.:
1076
+ arg1 = arg1 + 2 * np.pi
1077
+ arg2 = rijk+y[j]
1078
+ arg3 = rijk+x[i]
1079
+ arg2 = np.log(arg2)
1080
+ arg3 = np.log(arg3)
1081
+ sumi += ijk*(z[k]*arg1-x[i]*arg2-y[j]*arg3)
1082
+ gval[ii, jj] = sumi
1083
+
1084
+ return gval
1085
+
1086
+
1087
+ #@jit("f8[:,:,:](i4, i4, f8[:,:], f8[:,:], f8[:,:], f8[:,:], i4[:,:], " +
1088
+ # "f8[:,:], f8[:,:], f8[:,:], f8[:], f8[:,:], " +
1089
+ # "i4[:], f8[:,:], f8[:], f8[:], f8[:], f8[:,:,:])",
1090
+ # nopython=True)
1091
+ @jit(nopython=True)
1092
+ def gm3d(npro, nstn, X, Y, edge, corner, face, Hx, Hy, Hz, Pd, Un,
1093
+ indx, crs, p1, p2, p3, mgval):
1094
+ """ grvmag 3d """
1095
+
1096
+ flimit = 64*np.spacing(1)
1097
+ omega = 0.0
1098
+ dp1 = 1.0
1099
+ I = 1.0
1100
+
1101
+ for pr in range(npro):
1102
+ for st in range(nstn):
1103
+ x = X[pr, st]
1104
+ y = Y[pr, st]
1105
+ for f in range(6):
1106
+ for g in range(4):
1107
+ cindx = face[f, g]
1108
+ crs[g, 0] = corner[cindx, 0] - x
1109
+ crs[g, 1] = corner[cindx, 1] - y
1110
+ crs[g, 2] = corner[cindx, 2]
1111
+
1112
+ p = 0
1113
+ q = 0
1114
+ r = 0
1115
+ eno1 = 4*f
1116
+ W = -2*np.pi
1117
+ l = Un[f, 0]
1118
+ m = Un[f, 1]
1119
+ n = Un[f, 2]
1120
+
1121
+ for t in range(4):
1122
+ p1[0] = crs[indx[t], 0]
1123
+ p1[1] = crs[indx[t], 1]
1124
+ p1[2] = crs[indx[t], 2]
1125
+ p2[0] = crs[indx[t+1], 0]
1126
+ p2[1] = crs[indx[t+1], 1]
1127
+ p2[2] = crs[indx[t+1], 2]
1128
+ p3[0] = crs[indx[t+2], 0]
1129
+ p3[1] = crs[indx[t+2], 1]
1130
+ p3[2] = crs[indx[t+2], 2]
1131
+ ###############################################################################
1132
+ ang = 0
1133
+ anout = p1[0]*l+p1[1]*m+p1[2]*n
1134
+
1135
+ if anout > flimit:
1136
+ n10 = p2[1]*p3[2] - p2[2]*p3[1]
1137
+ n11 = p2[2]*p3[0] - p2[0]*p3[2]
1138
+ n12 = p2[0]*p3[1] - p2[1]*p3[0]
1139
+
1140
+ n20 = p2[1]*p1[2] - p2[2]*p1[1]
1141
+ n21 = p2[2]*p1[0] - p2[0]*p1[2]
1142
+ n22 = p2[0]*p1[1] - p2[1]*p1[0]
1143
+
1144
+ else:
1145
+ n10 = p2[1]*p1[2] - p2[2]*p1[1]
1146
+ n11 = p2[2]*p1[0] - p2[0]*p1[2]
1147
+ n12 = p2[0]*p1[1] - p2[1]*p1[0]
1148
+
1149
+ n20 = p2[1]*p3[2] - p2[2]*p3[1]
1150
+ n21 = p2[2]*p3[0] - p2[0]*p3[2]
1151
+ n22 = p2[0]*p3[1] - p2[1]*p3[0]
1152
+
1153
+ pn1 = np.sqrt(n10*n10+n11*n11+n12*n12)
1154
+ pn2 = np.sqrt(n20*n20+n21*n21+n22*n22)
1155
+
1156
+ if (pn1 <= flimit) or (pn2 <= flimit):
1157
+ ang = np.nan
1158
+ else:
1159
+ n10 = n10/pn1
1160
+ n11 = n11/pn1
1161
+ n12 = n12/pn1
1162
+ n20 = n20/pn2
1163
+ n21 = n21/pn2
1164
+ n22 = n22/pn2
1165
+
1166
+ rrr = n10*n20+n11*n21+n12*n22
1167
+ ang = np.arccos(rrr)
1168
+
1169
+ perp = n10*p3[0]+n11*p3[1]+n12*p3[2]
1170
+ if anout > flimit:
1171
+ perp = n10*p1[0]+n11*p1[1]+n12*p1[2]
1172
+
1173
+ if perp < -flimit: # points p1,p2,p3 in cw order
1174
+ ang = 2*np.pi-ang
1175
+
1176
+ if abs(anout) <= flimit:
1177
+ ang = 0
1178
+ ###############################################################################
1179
+ W += ang
1180
+
1181
+ eno2 = eno1+t # Edge no
1182
+ L = edge[eno2, 3]
1183
+
1184
+ r12 = (np.sqrt(p1[0]*p1[0]+p1[1]*p1[1]+p1[2]*p1[2]) +
1185
+ np.sqrt(p2[0]*p2[0]+p2[1]*p2[1]+p2[2]*p2[2]))
1186
+ I = (1/L)*np.log((r12+L)/(r12-L))
1187
+
1188
+ p += I*edge[eno2, 0]
1189
+ q += I*edge[eno2, 1]
1190
+ r += I*edge[eno2, 2]
1191
+
1192
+ # From omega, l, m, n PQR get components of field due to face f
1193
+ dp1 = l*crs[0, 0]+m*crs[0, 1]+n*crs[0, 2]
1194
+ if dp1 < 0.:
1195
+ omega = W
1196
+ else:
1197
+ omega = -W
1198
+
1199
+ gmtf1 = l*omega+n*q-m*r
1200
+ gmtf2 = m*omega+l*r-n*p
1201
+ gmtf3 = n*omega+m*p-l*q
1202
+
1203
+ Hx[pr, st] = Hx[pr, st]+Pd[f]*gmtf1
1204
+ Hy[pr, st] = Hy[pr, st]+Pd[f]*gmtf2
1205
+ Hz[pr, st] = Hz[pr, st]+Pd[f]*gmtf3
1206
+
1207
+ # Gx[pr, st] = Gx[pr, st]-dp1*gmtf1
1208
+ # Gy[pr, st] = Gy[pr, st]-dp1*gmtf2
1209
+ # Gz[pr, st] = Gz[pr, st]-dp1*gmtf3
1210
+
1211
+ for pr in range(npro):
1212
+ for st in range(nstn):
1213
+ mgval[0, pr, st] = Hx[pr, st]
1214
+ mgval[1, pr, st] = Hy[pr, st]
1215
+ mgval[2, pr, st] = Hz[pr, st]
1216
+ # mgval[3, pr, st] = Gx[pr, st]
1217
+ # mgval[4, pr, st] = Gy[pr, st]
1218
+ # mgval[5, pr, st] = Gz[pr, st]
1219
+
1220
+ return mgval
1221
+
1222
+
1223
+ def dircos(incl, decl, azim):
1224
+ """
1225
+ Subroutine DIRCOS computes direction cosines from inclination
1226
+ and declination.
1227
+
1228
+ Input parameters:
1229
+ incl: inclination in degrees positive below horizontal.
1230
+ decl: declination in degrees positive east of true north.
1231
+ azim: azimuth of x axis in degrees positive east of north.
1232
+
1233
+ Output parameters:
1234
+ a,b,c: the three direction cosines.
1235
+ """
1236
+
1237
+ d2rad = np.pi/180.
1238
+ xincl = incl*d2rad
1239
+ xdecl = decl*d2rad
1240
+ xazim = azim*d2rad
1241
+ aaa = np.cos(xincl)*np.cos(xdecl-xazim)
1242
+ bbb = np.cos(xincl)*np.sin(xdecl-xazim)
1243
+ ccc = np.sin(xincl)
1244
+ return aaa, bbb, ccc
1245
+
1246
+
1247
+ def dat_extent(dat, axes):
1248
+ """ Gets the extent of the dat variable """
1249
+ left = dat.tlx
1250
+ top = dat.tly
1251
+ right = left + dat.cols*dat.xdim
1252
+ bottom = top - dat.rows*dat.ydim
1253
+
1254
+ if (right-left) > 10000 or (top-bottom) > 10000:
1255
+ axes.xaxis.set_label_text("Eastings (km)")
1256
+ axes.yaxis.set_label_text("Northings (km)")
1257
+ left /= 1000.
1258
+ right /= 1000.
1259
+ top /= 1000.
1260
+ bottom /= 1000.
1261
+ else:
1262
+ axes.xaxis.set_label_text("Eastings (m)")
1263
+ axes.yaxis.set_label_text("Northings (m)")
1264
+
1265
+ return (left, right, bottom, top)