HolyPeckers
HolyPeckers

Reputation: 45

How to match two similar but not exact sets of coordinates in python

I have two sets of nodes. Node set A contains a list of node ID and the node XYZ coordinates, ex: (ID: int, [x: float, y: float, z: float]). Node set B contains a node temperature and the nodes XYZ coordinates. All of the nodes in set A should (but not necessarily) be found in set B but set B can also contain additional nodes. I need to match the nodes in set A to their corresponding nodes in set B based on their coordinates. The main issue being that their coordinates are not exact matches (float errors exist).

The solution should preferably avoid non standard libraries. I have coded what I believe would not be the best solution to the problem. I've attempted to create a dict containing set B. The keys consists of a tuple containing truncated coordinates with the temperatures being the values. I then use truncated set A coordinates to query the dict. I am wondering if there is a more elegant and accurate way of going about the problem?

Upvotes: 1

Views: 704

Answers (1)

cglacet
cglacet

Reputation: 10912

You can probably make use of math.isclose, it requires a bit of tuning depending on your inputs (carefully selecting rel_tol and abs_tol based on your use case).

Any many cases default values will do:

import itertools
import math

def matching_temperatures(A, B):
  temperatures = dict()

  for a, b in itertools.product(A, B):
    a_id, a_xyz = a
    b_temp, b_xyz = b
    if all(math.isclose(i, j) for i, j in zip(a_xyz, b_xyz)):
      temperatures[a_id] = b_temp

  return temperatures

# Let's say our coordinates have the following error margin:
epsilon = 1e-9

A = (
  ('a', (3.3, 2.2, 1.1)), 
  ('b', (10.1, 20.2, 30.3))
)
# Same coordinates as A with a ±epsilon error: 
B = (
  ('1°c', (3.3+epsilon, 2.2-epsilon, 1.1+epsilon)), 
  ('2°c', (10.1-epsilon, 20.2+epsilon, 30.3+epsilon))
)

print(matching_temperatures(A, B))

In this particular example, this will print {'a': '1°c', 'b': '2°c'}.

But in some cases (for example your errors are greater than the default rel_tol of 1e-9) then you will need to specify this: math.isclose(i, j, rel_tol=your_epsilon).

Upvotes: 2

Related Questions