forked from floli/PyRBF
-
Notifications
You must be signed in to change notification settings - Fork 2
/
basisfunctions.py
183 lines (137 loc) · 5.3 KB
/
basisfunctions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import functools
import numpy as np
import scipy, scipy.special
class Basisfunction():
has_shape_param = False
def __init__(self, shape_parameter = None):
self.s = shape_parameter
def __str__(self):
return type(self).__name__
@classmethod
def shape_param_from_m(cls, m, in_mesh):
""" m is the support radius expressed in multiples of the mesh width.
Default implementation for basis function that don't have a shape parameter or
the parameter can not be interpreted that way. """
return m
def shaped(self, m, in_mesh):
return functools.partial(self.__call__, shape = self.shape_param(m, in_mesh))
@staticmethod
def h_max(mesh):
""" Finds the greatest distance to each vertices nearest neighbor. """
h_max = 0
if mesh.ndim == 1:
mesh = mesh[:, np.newaxis]
for i in mesh:
distances = np.linalg.norm(mesh - i, axis=1)
h_max = np.max([ np.min(distances[distances != 0]), h_max])
return h_max
class Gaussian(Basisfunction):
has_shape_param = True
def __init__(self, shape_parameter):
self.s = shape_parameter
def __call__(self, radius):
radius = np.atleast_1d(radius)
threshold = np.sqrt( - np.log(1e-9) ) / self.s
result = np.exp( -np.power(self.s * np.abs(radius), 2))
result[ radius > threshold ] = 0;
#print("result: ", result)
return result
@classmethod
def shape_param_from_m(cls, m, in_mesh):
h_max = cls.h_max(in_mesh)
return np.sqrt(-np.log(1e-9)) / (m*h_max)
class GaussianAdaptive(Basisfunction):
has_shape_param = True
def __init__(self, shape_parameter):
self.s = shape_parameter
def __call__(self, radius, limit):
radius = np.atleast_1d(radius)
threshold = np.sqrt( - np.log(10e-9) ) / limit
result = np.exp( -np.power(limit * np.abs(radius), 2))
result[ radius > threshold ] = 0;
#print("result: ", result)
return result
@classmethod
def shape_param_from_m(cls, m, in_mesh):
h_max = cls.h_max(in_mesh)
return np.sqrt(-np.log(1e-9)) / (m*h_max)
class ThinPlateSplines(Basisfunction):
def __call__(self, radius):
""" Thin Plate Splines Basis Function """
# Avoids the division by zero in np.log
return scipy.special.xlogy(np.power(radius, 2), np.abs(radius))
class InverseMultiQuadrics(Basisfunction):
has_shape_param = True
def __init__(self, shape_parameter):
self.s = shape_parameter
def __call__(self, radius):
return 1.0 / np.sqrt(np.power(self.s, 2) + np.power(radius, 2));
class MultiQuadrics(Basisfunction):
has_shape_param = True
def __init__(self, shape_parameter):
self.s = shape_parameter
def __call__(self, radius):
return np.sqrt(np.power(self.s, 2) + np.power(radius, 2))
class VolumeSplines(Basisfunction):
def __call__(self, radius):
return np.abs(radius)
class CompactThinPlateSplineC2(Basisfunction):
has_shape_param = True
def __init__(self, shape_parameter):
self.s = shape_parameter
def __call__(self, radius):
radius = np.abs(radius)
result = np.zeros_like(radius)
p = radius / self.s
result = 1 - 30*np.power(p, 2) - 10*np.power(p, 3) + 45*np.power(p, 4) - 6*np.power(p, 5)
result =- scipy.special.xlogy(60*np.power(p,3), p)
result[ radius >= self.s ] = 0
return result
@classmethod
def shape_param_from_m(cls, m, in_mesh):
h_max = cls.h_max(in_mesh)
return m * h_max
class CompactPolynomialC0(Basisfunction):
has_shape_param = True
def __init__(self, shape_parameter):
self.s = shape_parameter
def __call__(self, radius):
radius = np.abs(radius)
result = np.zeros_like(radius)
p = radius / self.s
result = np.power(1-p, 2)
result[ radius >= self.s ] = 0
return result
@classmethod
def shape_param_from_m(cls, m, in_mesh):
h_max = cls.h_max(in_mesh)
return m * h_max
class CompactPolynomialC6(Basisfunction):
has_shape_param = True
def __init__(self, shape_parameter):
self.s = shape_parameter
def __call__(self, radius):
radius = np.abs(radius)
result = np.zeros_like(radius)
p = radius / self.s
result = np.power(1-p, 8) * (32*np.power(p, 3) + 25*np.power(p, 2) + 8*p + 1)
result[ radius >= self.s ] = 0
return result
@classmethod
def shape_param_from_m(cls, m, in_mesh):
h_max = cls.h_max(in_mesh)
return m * h_max
def rescaleBasisfunction(func, m, in_mesh):
""" Returns the basis function shape parameter, so that it has decayed to < 10^9 at x = m*h. h being the maximum cell width. Assumes in_mesh being sorted."""
try:
h = np.max(in_mesh[1:] - in_mesh[:-1])
except IndexError:
h = in_mesh
if func == Gaussian:
s = np.sqrt(-np.log(1e-3)) / (m*h)
elif func == ThinPlateSPlines:
return 0 # TPS has no shape parameter
else:
raise NotImplemented
# print("Maximum input mesh distance h =", h, " resulting in shape parameter =", s)
return s