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.
- pygmi-2.2.7/LICENSE.txt +623 -0
- pygmi-2.2.7/MANIFEST.in +7 -0
- pygmi-2.2.7/PKG-INFO +47 -0
- pygmi-2.2.7/README.md +55 -0
- pygmi-2.2.7/README.rst +20 -0
- pygmi-2.2.7/log.txt +242 -0
- pygmi-2.2.7/pygmi/__init__.py +22 -0
- pygmi-2.2.7/pygmi/clust/__init__.py +4 -0
- pygmi-2.2.7/pygmi/clust/crisp_clust.py +708 -0
- pygmi-2.2.7/pygmi/clust/datatypes.py +65 -0
- pygmi-2.2.7/pygmi/clust/fuzzy_clust.py +906 -0
- pygmi-2.2.7/pygmi/clust/graphs.py +421 -0
- pygmi-2.2.7/pygmi/clust/graphtool.py +667 -0
- pygmi-2.2.7/pygmi/clust/menu.py +139 -0
- pygmi-2.2.7/pygmi/clust/var_ratio.py +92 -0
- pygmi-2.2.7/pygmi/clust/xie_beni.py +93 -0
- pygmi-2.2.7/pygmi/helpdocs/linepointer.png +0 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.main.html +31 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.ddisp.html +15 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.iodefs.exportkmz.html +13 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.iodefs.importpicture.html +16 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.layer.html +17 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.mext.html +44 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.misc.rangedcopy.html +16 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.param.html +37 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.prof.html +32 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.pview.html +26 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.gradients.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.tilt.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.visibility.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datagrid.html +13 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datamerge.html +11 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datareproj.html +11 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.rtp.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.ginterp.html +31 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.igrf.html +20 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.normalisation.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.smooth.html +22 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.tiltdepth.html +20 -0
- pygmi-2.2.7/pygmi/images/Help.png +0 -0
- pygmi-2.2.7/pygmi/images/bringtofront.png +0 -0
- pygmi-2.2.7/pygmi/images/cgs2.emf +0 -0
- pygmi-2.2.7/pygmi/images/delete.png +0 -0
- pygmi-2.2.7/pygmi/images/linepointer.png +0 -0
- pygmi-2.2.7/pygmi/images/logo256.ico +0 -0
- pygmi-2.2.7/pygmi/images/logo256.png +0 -0
- pygmi-2.2.7/pygmi/images/pointer.png +0 -0
- pygmi-2.2.7/pygmi/images/pygmi.png +0 -0
- pygmi-2.2.7/pygmi/images/sendtoback.png +0 -0
- pygmi-2.2.7/pygmi/main.py +1037 -0
- pygmi-2.2.7/pygmi/menu_default.py +327 -0
- pygmi-2.2.7/pygmi/misc.py +147 -0
- pygmi-2.2.7/pygmi/pfmod/__init__.py +6 -0
- pygmi-2.2.7/pygmi/pfmod/cubes.py +1488 -0
- pygmi-2.2.7/pygmi/pfmod/datatypes.py +292 -0
- pygmi-2.2.7/pygmi/pfmod/grvmag3d.py +1265 -0
- pygmi-2.2.7/pygmi/pfmod/iodefs.py +1001 -0
- pygmi-2.2.7/pygmi/pfmod/menu.py +107 -0
- pygmi-2.2.7/pygmi/pfmod/misc.py +301 -0
- pygmi-2.2.7/pygmi/pfmod/pfmod.py +248 -0
- pygmi-2.2.7/pygmi/pfmod/tab_ddisp.py +425 -0
- pygmi-2.2.7/pygmi/pfmod/tab_layer.py +490 -0
- pygmi-2.2.7/pygmi/pfmod/tab_mext.py +544 -0
- pygmi-2.2.7/pygmi/pfmod/tab_param.py +548 -0
- pygmi-2.2.7/pygmi/pfmod/tab_prof.py +946 -0
- pygmi-2.2.7/pygmi/pfmod/tab_pview.py +740 -0
- pygmi-2.2.7/pygmi/raster/IGRF11.COF +1635 -0
- pygmi-2.2.7/pygmi/raster/__init__.py +14 -0
- pygmi-2.2.7/pygmi/raster/cooper.py +718 -0
- pygmi-2.2.7/pygmi/raster/dataprep.py +1640 -0
- pygmi-2.2.7/pygmi/raster/datatypes.py +123 -0
- pygmi-2.2.7/pygmi/raster/equation_editor.py +256 -0
- pygmi-2.2.7/pygmi/raster/ginterp.py +1901 -0
- pygmi-2.2.7/pygmi/raster/graphs.py +531 -0
- pygmi-2.2.7/pygmi/raster/igrf.py +860 -0
- pygmi-2.2.7/pygmi/raster/iodefs.py +813 -0
- pygmi-2.2.7/pygmi/raster/menu.py +307 -0
- pygmi-2.2.7/pygmi/raster/normalisation.py +187 -0
- pygmi-2.2.7/pygmi/raster/show_table.py +245 -0
- pygmi-2.2.7/pygmi/raster/smooth.py +406 -0
- pygmi-2.2.7/pygmi/raster/tiltdepth.py +590 -0
- pygmi-2.2.7/pygmi/seis/__init__.py +0 -0
- pygmi-2.2.7/pygmi/seis/beachball.py +751 -0
- pygmi-2.2.7/pygmi/seis/datatypes.py +605 -0
- pygmi-2.2.7/pygmi/seis/del_rec.py +410 -0
- pygmi-2.2.7/pygmi/seis/iodefs.py +1261 -0
- pygmi-2.2.7/pygmi/seis/menu.py +136 -0
- pygmi-2.2.7/pygmi/seis/scan_imp.py +795 -0
- pygmi-2.2.7/pygmi/test/__init__.py +6 -0
- pygmi-2.2.7/pygmi/test/pfmod.py +212 -0
- pygmi-2.2.7/pygmi/test/tests.py +39 -0
- pygmi-2.2.7/pygmi/vector/__init__.py +7 -0
- pygmi-2.2.7/pygmi/vector/datatypes.py +74 -0
- pygmi-2.2.7/pygmi/vector/graphs.py +443 -0
- pygmi-2.2.7/pygmi/vector/iodefs.py +345 -0
- pygmi-2.2.7/pygmi/vector/menu.py +127 -0
- pygmi-2.2.7/pygmi.egg-info/PKG-INFO +47 -0
- pygmi-2.2.7/pygmi.egg-info/SOURCES.txt +105 -0
- pygmi-2.2.7/pygmi.egg-info/dependency_links.txt +1 -0
- pygmi-2.2.7/pygmi.egg-info/entry_points.txt +3 -0
- pygmi-2.2.7/pygmi.egg-info/not-zip-safe +1 -0
- pygmi-2.2.7/pygmi.egg-info/requires.txt +7 -0
- pygmi-2.2.7/pygmi.egg-info/top_level.txt +1 -0
- pygmi-2.2.7/quickstart.py +35 -0
- pygmi-2.2.7/setup.cfg +8 -0
- 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)
|