LoopStructural 1.0.9__cp36-cp36m-win32.whl

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 (77) hide show
  1. LoopStructural/__init__.py +36 -0
  2. LoopStructural/analysis/__init__.py +2 -0
  3. LoopStructural/analysis/_fault_displacement.py +67 -0
  4. LoopStructural/analysis/_fault_intersection.py +36 -0
  5. LoopStructural/analysis/_plane_fit.py +43 -0
  6. LoopStructural/datasets/__init__.py +12 -0
  7. LoopStructural/datasets/_base.py +65 -0
  8. LoopStructural/datasets/data/claudius.csv +21049 -0
  9. LoopStructural/datasets/data/claudiusbb.txt +2 -0
  10. LoopStructural/datasets/data/duplex.csv +126 -0
  11. LoopStructural/datasets/data/duplexbb.txt +2 -0
  12. LoopStructural/datasets/data/intrusion.csv +1017 -0
  13. LoopStructural/datasets/data/intrusionbb.txt +2 -0
  14. LoopStructural/datasets/data/onefoldbb.txt +2 -0
  15. LoopStructural/datasets/data/onefolddata.csv +2226 -0
  16. LoopStructural/datasets/data/refolded_bb.txt +2 -0
  17. LoopStructural/datasets/data/refolded_fold.csv +2126 -0
  18. LoopStructural/interpolators/__init__.py +34 -0
  19. LoopStructural/interpolators/base_structured_3d_support.py +101 -0
  20. LoopStructural/interpolators/cython/__init__.py +0 -0
  21. LoopStructural/interpolators/cython/dsi_helper.c +31046 -0
  22. LoopStructural/interpolators/cython/dsi_helper.cp36-win32.pyd +0 -0
  23. LoopStructural/interpolators/discrete_fold_interpolator.py +202 -0
  24. LoopStructural/interpolators/discrete_interpolator.py +584 -0
  25. LoopStructural/interpolators/finite_difference_interpolator.py +399 -0
  26. LoopStructural/interpolators/geological_interpolator.py +197 -0
  27. LoopStructural/interpolators/operator.py +61 -0
  28. LoopStructural/interpolators/piecewiselinear_interpolator.py +437 -0
  29. LoopStructural/interpolators/structured_grid.py +421 -0
  30. LoopStructural/interpolators/structured_tetra.py +681 -0
  31. LoopStructural/interpolators/surfe_wrapper.py +118 -0
  32. LoopStructural/modelling/__init__.py +46 -0
  33. LoopStructural/modelling/core/__init__.py +0 -0
  34. LoopStructural/modelling/core/geological_model.py +1513 -0
  35. LoopStructural/modelling/core/geological_model_graph.py +880 -0
  36. LoopStructural/modelling/core/stratigraphic_column.py +5 -0
  37. LoopStructural/modelling/fault/__init__.py +4 -0
  38. LoopStructural/modelling/fault/fault_builder.py +143 -0
  39. LoopStructural/modelling/fault/fault_function.py +188 -0
  40. LoopStructural/modelling/fault/fault_function_feature.py +76 -0
  41. LoopStructural/modelling/fault/fault_segment.py +298 -0
  42. LoopStructural/modelling/features/__init__.py +8 -0
  43. LoopStructural/modelling/features/cross_product_geological_feature.py +90 -0
  44. LoopStructural/modelling/features/geological_feature.py +252 -0
  45. LoopStructural/modelling/features/geological_feature_builder.py +414 -0
  46. LoopStructural/modelling/features/lambda_geological_feature.py +36 -0
  47. LoopStructural/modelling/features/region_feature.py +34 -0
  48. LoopStructural/modelling/features/structural_frame.py +133 -0
  49. LoopStructural/modelling/features/structural_frame_builder.py +206 -0
  50. LoopStructural/modelling/features/unconformity_feature.py +74 -0
  51. LoopStructural/modelling/fold/__init__.py +8 -0
  52. LoopStructural/modelling/fold/fold.py +143 -0
  53. LoopStructural/modelling/fold/fold_rotation_angle.py +133 -0
  54. LoopStructural/modelling/fold/fold_rotation_angle_feature.py +58 -0
  55. LoopStructural/modelling/fold/foldframe.py +193 -0
  56. LoopStructural/modelling/fold/svariogram.py +180 -0
  57. LoopStructural/utils/__init__.py +18 -0
  58. LoopStructural/utils/bounding_box.py +21 -0
  59. LoopStructural/utils/exceptions.py +10 -0
  60. LoopStructural/utils/helper.py +382 -0
  61. LoopStructural/utils/logging.py +60 -0
  62. LoopStructural/utils/map2loop.py +353 -0
  63. LoopStructural/utils/regions.py +11 -0
  64. LoopStructural/utils/utils.py +69 -0
  65. LoopStructural/visualisation/__init__.py +31 -0
  66. LoopStructural/visualisation/map_viewer.py +322 -0
  67. LoopStructural/visualisation/model_plotter.py +17 -0
  68. LoopStructural/visualisation/model_visualisation.py +1113 -0
  69. LoopStructural/visualisation/rotation_angle_plotter.py +83 -0
  70. LoopStructural/visualisation/sphinx_scraper.py +34 -0
  71. LoopStructural/visualisation/stratigraphic_column.py +60 -0
  72. LoopStructural-1.0.9.dist-info/LICENSE +21 -0
  73. LoopStructural-1.0.9.dist-info/METADATA +19 -0
  74. LoopStructural-1.0.9.dist-info/RECORD +77 -0
  75. LoopStructural-1.0.9.dist-info/WHEEL +5 -0
  76. LoopStructural-1.0.9.dist-info/top_level.txt +2 -0
  77. tests/__init__.py +0 -0
@@ -0,0 +1,584 @@
1
+ """
2
+ Discrete interpolator base for least squares
3
+ """
4
+ import logging
5
+
6
+ import numpy as np
7
+ from scipy.sparse import coo_matrix, bmat, eye
8
+ from scipy.sparse import linalg as sla
9
+
10
+ from LoopStructural.interpolators.geological_interpolator import \
11
+ GeologicalInterpolator
12
+
13
+ from LoopStructural.utils import getLogger
14
+ logger = getLogger(__name__)
15
+
16
+
17
+ class DiscreteInterpolator(GeologicalInterpolator):
18
+ """
19
+
20
+ """
21
+ def __init__(self, support):
22
+ """
23
+ Base class for a discrete interpolator e.g. piecewise linear or finite difference which is
24
+ any interpolator that solves the system using least squares approximation
25
+
26
+ Parameters
27
+ ----------
28
+ support
29
+ A discrete mesh with, nodes, elements, etc
30
+ """
31
+ GeologicalInterpolator.__init__(self)
32
+ self.B = []
33
+ self.support = support
34
+ self.region_function = lambda xyz : np.ones(xyz.shape[0],dtype=int)
35
+ # self.region_map[self.region] = np.array(range(0,
36
+ # len(self.region_map[self.region])))
37
+ self.shape = 'rectangular'
38
+ if self.shape == 'square':
39
+ self.B = np.zeros(self.nx)
40
+ self.c_ = 0
41
+ self.A = [] # sparse matrix storage coo format
42
+ self.col = []
43
+ self.row = [] # sparse matrix storage
44
+ self.solver = None
45
+ self.eq_const_C = []
46
+ self.eq_const_row = []
47
+ self.eq_const_col = []
48
+ self.eq_const_d = []
49
+ self.eq_const_c_ = 0
50
+ self.constraints = {}
51
+ self.interpolation_weights= {}
52
+ logger.info("Creating discrete interpolator with {} degrees of freedom".format(self.nx))
53
+
54
+ @property
55
+ def nx(self):
56
+ return len(self.support.nodes[self.region])
57
+
58
+ @property
59
+ def region(self):
60
+ return self.region_function(self.support.nodes)
61
+
62
+ @property
63
+ def region_map(self):
64
+ region_map = np.zeros(self.support.n_nodes).astype(int)
65
+ region_map[self.region] = np.array(
66
+ range(0, len(region_map[self.region])))
67
+ return region_map
68
+ def set_property_name(self, propertyname):
69
+ """
70
+ Set the property name attribute, this is usually used to
71
+ save the property on the support
72
+
73
+ Parameters
74
+ ----------
75
+ propertyname
76
+
77
+ Returns
78
+ -------
79
+
80
+ """
81
+ self.propertyname = propertyname
82
+
83
+ def set_region(self, region=None):
84
+ """
85
+ Set the region of the support the interpolator is working on
86
+
87
+ Parameters
88
+ ----------
89
+ region - function(position)
90
+ return true when in region, false when out
91
+
92
+ Returns
93
+ -------
94
+
95
+ """
96
+ # evaluate the region function on the support to determine
97
+ # which nodes are inside update region map and degrees of freedom
98
+ self.region_function = region
99
+ logger.info("Interpolation now uses region and has {} degrees of freedom".format(self.nx))
100
+
101
+ def set_interpolation_weights(self, weights):
102
+ """
103
+ Set the interpolation weights dictionary
104
+
105
+ Parameters
106
+ ----------
107
+ weights - dictionary
108
+ Entry of new weights to assign to self.interpolation_weights
109
+
110
+ Returns
111
+ -------
112
+
113
+ """
114
+ for key in weights:
115
+ self.up_to_date = False
116
+ self.interpolation_weights[key] = weights[key]
117
+
118
+ def reset(self):
119
+ """
120
+ Reset the interpolation constraints
121
+
122
+ """
123
+ logger.debug("Resetting interpolation constraints")
124
+ self.c_ = 0
125
+ self.A = [] # sparse matrix storage coo format
126
+ self.col = []
127
+ self.row = [] # sparse matrix storage
128
+ self.eq_const_C = []
129
+ self.eq_const_row = []
130
+ self.eq_const_col = []
131
+ self.eq_const_d = []
132
+ self.eq_const_c_ = 0
133
+ self.B = []
134
+ self.n_constraints = 0
135
+
136
+ def add_constraints_to_least_squares(self, A, B, idc, name='undefined'):
137
+ """
138
+ Adds constraints to the least squares system. Automatically works
139
+ out the row
140
+ index given the shape of the input arrays
141
+
142
+ Parameters
143
+ ----------
144
+ A : numpy array / list
145
+ RxC numpy array of constraints where C is number of columns,R rows
146
+ B : numpy array /list
147
+ B values array length R
148
+ idc : numpy array/list
149
+ RxC column index
150
+
151
+ Returns
152
+ -------
153
+ list of constraint ids
154
+
155
+ """
156
+ A = np.array(A)
157
+ B = np.array(B)
158
+ idc = np.array(idc)
159
+ nr = A.shape[0]
160
+ #logger.debug('Adding constraints to interpolator: {} {} {}'.format(A.shape[0]))
161
+ # print(A.shape,B.shape,idc.shape)
162
+ if A.shape != idc.shape:
163
+ return
164
+
165
+ if len(A.shape) > 2:
166
+ nr = A.shape[0] * A.shape[1]
167
+ A = A.reshape((A.shape[0]*A.shape[1],A.shape[2]))
168
+ idc = idc.reshape((idc.shape[0]*idc.shape[1],idc.shape[2]))
169
+ # going to assume if any are nan they are all nan
170
+ mask = np.any(np.isnan(A),axis=1)
171
+ A[mask,:] = 0
172
+ if np.any(np.isnan(idc)) or np.any(np.isnan(A)) or np.any(np.isnan(B)):
173
+ logger.warning("Constraints contain nan not adding constraints: {}".format(name))
174
+ # return
175
+
176
+ rows = np.arange(0, nr).astype(int)
177
+ rows += self.c_
178
+ constraint_ids = rows.copy()
179
+
180
+ if name in self.constraints:
181
+
182
+ self.constraints[name]['A'] = np.vstack([self.constraints[name]['A'],A])
183
+ self.constraints[name]['B'] = np.hstack([self.constraints[name]['B'], B])
184
+ self.constraints[name]['idc'] = np.vstack([self.constraints[name]['idc'],
185
+ idc])
186
+
187
+ if name not in self.constraints:
188
+ self.constraints[name] = {'node_indexes':constraint_ids,'A':A,'B':B.flatten(),'idc':idc}
189
+ rows = np.tile(rows, (A.shape[-1], 1)).T
190
+
191
+ self.c_ += nr
192
+ if self.shape == 'rectangular':
193
+ # don't add operator where it is = 0 to the sparse matrix!
194
+ A = A.flatten()
195
+ rows = rows.flatten()
196
+ idc = idc.flatten()
197
+ B = B.flatten()
198
+ mask = A == 0
199
+ self.A.extend(A[~mask].tolist())
200
+ self.row.extend(rows[~mask].tolist())
201
+ self.col.extend(idc[~mask].tolist())
202
+ self.B.extend(B.tolist())
203
+
204
+ def calculate_residual_for_constraints(self):
205
+ residuals = {}
206
+ for constraint_name, constraint in self.constraints:
207
+ residuals[constraint_name] = np.einsum('ij,ij->i',constraint['A'],self.c[constraint['idc'].astype(int)]) - constraint['B'].flatten()
208
+ return residuals
209
+ def remove_constraints_from_least_squares(self, name='undefined',
210
+ constraint_ids=None):
211
+ """
212
+ Remove constraints from the least squares system using the constraint ids
213
+ which corresponds to the rows in the interpolation matrix.
214
+
215
+ Parameters
216
+ ----------
217
+ constraint_ids : np.array(dtype=int)
218
+ id of constraints to remove
219
+
220
+ Returns
221
+ -------
222
+
223
+ """
224
+
225
+ if constraint_ids is None:
226
+ constraint_ids = self.constraints[name]
227
+ print("Removing {} {} constraints from least squares".format(len(constraint_ids), name))
228
+ A = np.array(self.A)
229
+ B = np.array(self.B)
230
+ col = np.array(self.col)
231
+ row = np.array(self.row)
232
+ mask = np.any((row[:,None] == constraint_ids[None,:]) == True,
233
+ axis=1)
234
+ # np.any((numbers[:, None] == np.array([0, 10, 30])[None, :]) == True,
235
+ # axis=1)
236
+ bmask = np.ones(B.shape,dtype=bool)
237
+ bmask[constraint_ids] = 0
238
+ self.A = A[~mask].tolist()
239
+ self.B = B[bmask]
240
+ self.col = col[~mask].tolist()
241
+ rowmax = np.max(row[mask])
242
+ rowrange = rowmax-np.min(row[mask])
243
+ # row[np.logical_and(~mask,row>rowmax)] -= rowrange
244
+ return row[~mask]
245
+
246
+ def add_equality_constraints(self, node_idx, values):
247
+ """
248
+ Adds hard constraints to the least squares system. For now this just
249
+ sets
250
+ the node values to be fixed using a lagrangian.
251
+
252
+ Parameters
253
+ ----------
254
+ node_idx : numpy array/list
255
+ int array of node indexes
256
+ values : numpy array/list
257
+ array of node values
258
+
259
+ Returns
260
+ -------
261
+
262
+ """
263
+ # map from mesh node index to region node index
264
+ gi = np.zeros(self.support.n_nodes)
265
+ gi[:] = -1
266
+ gi[self.region] = np.arange(0, self.nx)
267
+ idc = gi[node_idx]
268
+ outside = ~(idc == -1)
269
+
270
+ self.eq_const_C.extend(np.ones(idc[outside].shape[0]).tolist())
271
+ self.eq_const_col.extend(idc[outside].tolist())
272
+ self.eq_const_row.extend((np.arange(0, idc[outside].shape[0])))
273
+ self.eq_const_d.extend(values[outside].tolist())
274
+ self.eq_const_c_ += idc[outside].shape[0]
275
+
276
+ def add_tangent_ctr_pts(self, w=1.0):
277
+ """
278
+
279
+ Parameters
280
+ ----------
281
+ w : double
282
+
283
+
284
+ Returns
285
+ -------
286
+
287
+ """
288
+ points = self.get_tangent_constraints()
289
+ if points.shape[0] > 1:
290
+ self.add_gradient_orthogonal_constraint(points[:,:3],points[:,3:6],w)
291
+
292
+ def build_matrix(self, square=True, damp=True):
293
+ """
294
+ Assemble constraints into interpolation matrix. Adds equaltiy
295
+ constraints
296
+ using lagrange modifiers if necessary
297
+
298
+ Parameters
299
+ ----------
300
+ damp: bool
301
+ Flag whether damping should be added to the diagonal of the matrix
302
+ Returns
303
+ -------
304
+ Interpolation matrix and B
305
+ """
306
+
307
+ logger.info("Interpolation matrix is %i x %i"%(self.c_,self.nx))
308
+ cols = np.array(self.col)
309
+ A = coo_matrix((np.array(self.A), (np.array(self.row), \
310
+ cols)), shape=(self.c_, self.nx),
311
+ dtype=float) # .tocsr()
312
+ B = np.array(self.B)
313
+ if not square:
314
+ logger.info("Using rectangular matrix, equality constraints are not used")
315
+ return A, B
316
+ AAT = A.T.dot(A)
317
+ BT = A.T.dot(B)
318
+ # add a small number to the matrix diagonal to smooth the results
319
+ # can help speed up solving, but might also introduce some errors
320
+
321
+ if self.eq_const_c_ > 0:
322
+ logger.info("Equality block is %i x %i"%(self.eq_const_c_,self.nx))
323
+ # solving constrained least squares using
324
+ # | ATA CT | |c| = b
325
+ # | C 0 | |y| d
326
+ # where A is the interpoaltion matrix
327
+ # C is the equality constraint matrix
328
+ # b is the interpolation constraints to be honoured
329
+ # in a least squares sense
330
+ # and d are the equality constraints
331
+ # c are the node values and y are the
332
+ # lagrange multipliers#
333
+ C = coo_matrix(
334
+ (np.array(self.eq_const_C), (np.array(self.eq_const_row),
335
+ np.array(self.eq_const_col))),
336
+ shape=(self.eq_const_c_, self.nx))
337
+ d = np.array(self.eq_const_d)
338
+ AAT = bmat([[AAT, C.T], [C, None]])
339
+ BT = np.hstack([BT, d])
340
+ if damp:
341
+ logger.info("Adding eps to matrix diagonal")
342
+ AAT += eye(AAT.shape[0]) * np.finfo('float').eps
343
+ return AAT, BT
344
+
345
+ def _solve_lu(self, A, B):
346
+ """
347
+ Call scipy LU decomoposition
348
+
349
+ Parameters
350
+ ----------
351
+ A : scipy square sparse matrix
352
+ B : numpy vector
353
+
354
+ Returns
355
+ -------
356
+
357
+ """
358
+ lu = sla.splu(A.tocsc())
359
+ sol = lu.solve(B)
360
+ return sol[:self.nx]
361
+
362
+ def _solve_lsqr(self, A, B, **kwargs):
363
+ """
364
+ Call scipy lsqr
365
+
366
+ Parameters
367
+ ----------
368
+ A : rectangular sparse matrix
369
+ B : vector
370
+
371
+ Returns
372
+ -------
373
+
374
+ """
375
+
376
+ lsqrargs = {}
377
+ lsqrargs['tol'] = 1e-12
378
+ lsqrargs['atol'] = 0
379
+ if 'iter_lim' in kwargs:
380
+ logger.info("Using %i maximum iterations" % kwargs['iter_lim'])
381
+ lsqrargs['iter_lim'] = kwargs['iter_lim']
382
+ if 'damp' in kwargs:
383
+ logger.info("Using damping coefficient")
384
+ lsqrargs['damp'] = kwargs['damp']
385
+ if 'atol' in kwargs:
386
+ logger.info('Using a tolerance of %f' % kwargs['atol'])
387
+ lsqrargs['atol'] = kwargs['atol']
388
+ if 'btol' in kwargs:
389
+ logger.info('Using btol of %f' % kwargs['btol'])
390
+ lsqrargs['btol'] = kwargs['btol']
391
+ if 'show' in kwargs:
392
+ lsqrargs['show'] = kwargs['show']
393
+ if 'conlim' in kwargs:
394
+ lsqrargs['conlim'] = kwargs['conlim']
395
+ return sla.lsqr(A,B, **lsqrargs)[0]
396
+
397
+ def _solve_chol(self, A, B):
398
+ """
399
+ Call suitesparse cholmod through scikitsparse
400
+ LINUX ONLY!
401
+
402
+ Parameters
403
+ ----------
404
+ A : scipy.sparse.matrix
405
+ square sparse matrix
406
+ B : numpy array
407
+ RHS of equation
408
+
409
+ Returns
410
+ -------
411
+
412
+ """
413
+ try:
414
+ from sksparse.cholmod import cholesky
415
+ factor = cholesky(A.tocsc())
416
+ return factor(B)[:self.nx]
417
+ except ImportError:
418
+ logger.warning("Scikit Sparse not installed try using cg instead")
419
+ return False
420
+
421
+ def _solve_cg(self, A, B, precon=None, **kwargs):
422
+ """
423
+ Call scipy conjugate gradient
424
+
425
+ Parameters
426
+ ----------
427
+ A : scipy.sparse.matrix
428
+ square sparse matrix
429
+ B : numpy vector
430
+ precon : scipy.sparse.matrix
431
+ a preconditioner for the conjugate gradient system
432
+ kwargs
433
+ kwargs to pass to scipy solve e.g. atol, btol, callback etc
434
+
435
+ Returns
436
+ -------
437
+ numpy array
438
+ """
439
+ cgargs = {}
440
+ cgargs['tol'] = 1e-12
441
+ cgargs['atol'] = 0
442
+ if 'maxiter' in kwargs:
443
+ logger.info("Using %i maximum iterations"%kwargs['maxiter'])
444
+ cgargs['maxiter'] = kwargs['maxiter']
445
+ if 'x0' in kwargs:
446
+ logger.info("Using starting guess")
447
+ cgargs['x0'] = kwargs['x0']
448
+ if 'tol' in kwargs:
449
+ logger.info('Using tolerance of %f'%kwargs['tol'])
450
+ cgargs['tol'] = kwargs['tol']
451
+ if 'atol' in kwargs:
452
+ logger.info('Using atol of %f'%kwargs['atol'])
453
+ cgargs['atol'] = kwargs['atol']
454
+ if 'callback' in kwargs:
455
+ cgargs['callback'] = kwargs['callback']
456
+ if precon is not None:
457
+ cgargs['M'] = precon(A)
458
+ return sla.cg(A, B, **cgargs)[0][:self.nx]
459
+
460
+ def _solve_pyamg(self, A, B, tol=1e-12,x0=None,**kwargs):
461
+ """
462
+ Solve least squares system using pyamg algorithmic multigrid solver
463
+
464
+ Parameters
465
+ ----------
466
+ A : scipy.sparse.matrix
467
+ B : numpy array
468
+
469
+ Returns
470
+ -------
471
+
472
+ """
473
+ import pyamg
474
+ logger.info("Solving using pyamg: tol {}".format(tol))
475
+ return pyamg.solve(A, B, tol=tol, x0=x0, verb=False)[:self.nx]
476
+
477
+ def _solve(self, solver='cg', **kwargs):
478
+ """
479
+ Main entry point to run the solver and update the node value
480
+ attribute for the
481
+ discreteinterpolator class
482
+
483
+ Parameters
484
+ ----------
485
+ solver : string
486
+ solver e.g. cg, lu, chol, custom
487
+ kwargs
488
+ kwargs for solver e.g. maxiter, preconditioner etc, damping for
489
+
490
+ Returns
491
+ -------
492
+ bool
493
+ True if the interpolation is run
494
+
495
+ """
496
+ logger.info("Solving interpolation for {}".format(self.propertyname))
497
+
498
+ self.c = np.zeros(self.support.n_nodes)
499
+ self.c[:] = np.nan
500
+ damp = True
501
+ if 'damp' in kwargs:
502
+ damp = kwargs['damp']
503
+ if solver == 'lu':
504
+ logger.info("Forcing matrix damping for LU")
505
+ damp = True
506
+ if solver == 'lsqr':
507
+ A, B = self.build_matrix(False)
508
+ else:
509
+ A, B = self.build_matrix(damp=damp)
510
+
511
+ # run the chosen solver
512
+ if solver == 'cg':
513
+ logger.info("Solving using conjugate gradient")
514
+ self.c[self.region] = self._solve_cg(A, B, **kwargs)
515
+ if solver == 'chol':
516
+ self.c[self.region] = self._solve_chol(A, B)
517
+ if solver == 'lu':
518
+ logger.info("Solving using scipy LU")
519
+ self.c[self.region] = self._solve_lu(A, B)
520
+ if solver == 'pyamg':
521
+ try:
522
+ logger.info("Solving with pyamg solve")
523
+ self.c[self.region] = self._solve_pyamg(A, B,**kwargs)
524
+ except ImportError:
525
+ logger.warn("Pyamg not installed using cg instead")
526
+ self.c[self.region] = self._solve_cg(A, B)
527
+ if solver == 'lsqr':
528
+ self.c[self.region] = self._solve_lsqr(A, B, **kwargs)
529
+ if solver == 'external':
530
+ logger.warning("Using external solver")
531
+ self.c[self.region] = kwargs['external'](A, B)[:self.nx]
532
+ # check solution is not nan
533
+ # self.support.properties[self.propertyname] = self.c
534
+ if np.all(self.c == np.nan):
535
+ logger.warning("Solver not run, no scalar field")
536
+ # if solution is all 0, probably didn't work
537
+ if np.all(self.c[self.region] == 0):
538
+ logger.warning("No solution, {} scalar field 0. Add more data.".format(self.propertyname))
539
+
540
+ def update(self):
541
+ """
542
+ Check if the solver is up to date, if not rerun interpolation using
543
+ the previously used solver. If the interpolation has not been run
544
+ before it will
545
+ return False
546
+
547
+ Returns
548
+ -------
549
+ bool
550
+
551
+ """
552
+ if self.solver is None:
553
+ logging.debug("Cannot rerun interpolator")
554
+ return False
555
+ if not self.up_to_date:
556
+ self.setup_interpolator()
557
+ return self._solve(self.solver)
558
+
559
+ def evaluate_value(self, evaluation_points):
560
+ evaluation_points = np.array(evaluation_points)
561
+ evaluated = np.zeros(evaluation_points.shape[0])
562
+ mask = np.any(evaluation_points == np.nan, axis=1)
563
+
564
+ if evaluation_points[~mask, :].shape[0] > 0:
565
+ evaluated[~mask] = self.support.evaluate_value(
566
+ evaluation_points[~mask], self.c)
567
+ return evaluated
568
+
569
+ def evaluate_gradient(self, evaluation_points):
570
+ """
571
+ Evaluate the gradient of the scalar field at the evaluation points
572
+ Parameters
573
+ ----------
574
+ evaluation_points : np.array
575
+ xyz locations to evaluate the gradient
576
+
577
+ Returns
578
+ -------
579
+
580
+ """
581
+ if evaluation_points.shape[0] > 0:
582
+ return self.support.evaluate_gradient(evaluation_points,
583
+ self.c)
584
+ return np.zeros((0, 3))