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