Skip to content

Commit 1dc33ce

Browse files
committed
Incoporate review into crash handling
1 parent c5b3a6c commit 1dc33ce

6 files changed

Lines changed: 170 additions & 151 deletions

File tree

.github/workflows/run-unit-tests.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ jobs:
2424
pip3 install --user .
2525
pip3 uninstall -y pyprecice
2626
27-
- name: Run unit tests
27+
- name: Run micro_manager unit test
2828
working-directory: micro-manager/tests/unit
2929
run: python3 -m unittest test_micro_manager.py
30+
31+
- name: Run interpolation unit test
32+
working-directory: micro-manager/tests/unit
33+
run: python3 -m unittest test_interpolation.py
34+
35+
- name: Run micro simulation crash unit test
36+
working-directory: micro-manager/tests/unit
37+
run: python3 -m unittest test_micro_simulation_crash_handling.py

micro_manager/interpolation.py

Lines changed: 57 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -9,75 +9,89 @@ def __init__(self, logger):
99

1010
def get_nearest_neighbor_indices_local(
1111
self,
12-
all_local_coords,
13-
inter_point,
12+
all_local_coords: np.ndarray,
13+
inter_point: np.ndarray,
1414
k: int,
15-
inter_point_is_neighbor: bool = False,
1615
) -> np.ndarray:
1716
"""
1817
Get the indices of the k nearest neighbors of a point in a list of coordinates.
19-
Note: It can be chosen whether the point itself is considered as a neighbor or not.
20-
Args:
21-
all_local_coords: list
22-
List of coordinates of all points.
23-
inter_point:
24-
Coordinates of the point for which the neighbors are to be found.
25-
k: int
26-
inter_point_is_neighbor: bool, optional
27-
Decide whether the interpolation point is considered as its own neighbor.
28-
Defaults to False.
18+
If inter_point is part of all_local_coords, it is only considered one time less than it occurs.
19+
inter_point is expected to be in all_local_coords at most once.
2920
30-
Returns: np.ndarray
31-
of indices of the k nearest neighbors.
21+
Parameters
22+
----------
23+
all_local_coords : list
24+
List of coordinates of all points.
25+
inter_point : list | np.ndarray
26+
Coordinates of the point for which the neighbors are to be found.
27+
k : int
28+
Number of neighbors to consider.
29+
30+
Returns
31+
------
32+
neighbor_indices : np.ndarray
33+
Indices of the k nearest neighbors in all local points.
3234
"""
3335
assert (
34-
len(all_local_coords) > k
35-
), "Desired number of neighbors must be less than the number of all available neighbors."
36-
if not inter_point_is_neighbor:
37-
neighbors = NearestNeighbors(n_neighbors=k + 1).fit(all_local_coords)
36+
len(all_local_coords) >= k
37+
), "Desired number of neighbors must be less than or equal to the number of all available neighbors."
38+
# If the number of neighbors is larger than the number of all available neighbors, increase the number of neighbors
39+
# to be able to delete a neighbor if it coincides with the interpolation point.
40+
if len(all_local_coords) > k:
41+
k += 1
42+
neighbors = NearestNeighbors(n_neighbors=k).fit(all_local_coords)
3843

39-
dists, neighbor_indices = neighbors.kneighbors(
40-
[inter_point], return_distance=True
41-
)
44+
dists, neighbor_indices = neighbors.kneighbors(
45+
[inter_point], return_distance=True
46+
)
4247

43-
if np.min(dists) < 1e-10:
44-
argmin = np.argmin(dists)
45-
neighbor_indices = np.delete(neighbor_indices, argmin)
46-
else:
47-
argmax = np.argmax(dists)
48-
neighbor_indices = np.delete(neighbor_indices, argmax)
48+
# Check whether the inter_point is also part of the neighbor list and remove it.
49+
if np.min(dists) < 1e-16:
50+
argmin = np.argmin(dists)
51+
neighbor_indices = np.delete(neighbor_indices, argmin)
52+
# If point itself is not in neighbor list, remove neighbor with largest distance
53+
# to return the desired number of neighbors
4954
else:
50-
neighbors = NearestNeighbors(n_neighbors=k).fit(all_local_coords)
51-
neighbor_indices = neighbors.kneighbors(
52-
[inter_point], return_distance=False
53-
)
55+
argmax = np.argmax(dists)
56+
neighbor_indices = np.delete(neighbor_indices, argmax)
5457

5558
return neighbor_indices
5659

5760
def inv_dist_weighted_interp(
58-
self, neighbors: list, point, values: list
59-
) -> np.ndarray:
61+
self, neighbors: np.ndarray, point: np.ndarray, values
62+
):
6063
"""
6164
Interpolate a value at a point using inverse distance weighting.
65+
.. math::
66+
f(x) = (\sum_{i=1}^{n} \frac{f_i}{\Vert x_i - x \Vert^2}) / (\sum_{j=1}^{n} \frac{1}{\Vert x_j - x \Vert^2})
6267
63-
Args:
64-
neighbors: list
65-
Coordinates at which the values are known.
66-
point:
67-
Coordinates at which the value is to be interpolated.
68-
values: list
69-
Values at the known coordinates.
68+
Parameters
69+
----------
70+
neighbors : np.ndarray
71+
Coordinates at which the values are known.
72+
point : np.ndarray
73+
Coordinates at which the value is to be interpolated.
74+
values :
75+
Values at the known coordinates.
7076
71-
Returns: nd.array
77+
Returns
78+
-------
79+
interpol_val / summed_weights :
7280
Value at interpolation point.
7381
"""
7482
interpol_val = 0
7583
summed_weights = 0
84+
# iterate over all neighbors
7685
for inx in range(len(neighbors)):
86+
# compute the squared norm of the difference between interpolation point and neighbor
7787
norm = np.linalg.norm(np.array(neighbors[inx]) - np.array(point)) ** 2
78-
if norm < 1e-10:
88+
# If interpolation point is already part of the data it is returned as the interpolation result
89+
# This avoids division by zero
90+
if norm < 1e-16:
7991
return values[inx]
92+
# update interpolation value
8093
interpol_val += values[inx] / norm
94+
# extend normalization factor
8195
summed_weights += 1 / norm
8296

8397
return interpol_val / summed_weights

0 commit comments

Comments
 (0)