Skip to content

Commit

Permalink
Merge pull request #81 from EOMYS-Public/master
Browse files Browse the repository at this point in the history
Add unique_tol/union1d_tol/intersect1d_tol functions + tests
  • Loading branch information
helene-t authored Dec 3, 2021
2 parents db9dcbf + 0c9b008 commit 183cfc3
Show file tree
Hide file tree
Showing 8 changed files with 301 additions and 105 deletions.
4 changes: 2 additions & 2 deletions SciDataTool/Functions/filter_spectral_leakage.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import numpy as np
import numpy.linalg as np_lin

from SciDataTool.Functions.unique_tol import unique_tol
from SciDataTool.Functions.set_routines import unique_tol


def filter_spectral_leakage(
Expand Down Expand Up @@ -46,7 +46,7 @@ def filter_spectral_leakage(
"""

# Expand theoretical frequencies to negative values
freqs_th = unique_tol(np.concatenate((freqs_th, -freqs_th), axis=0))["b"]
freqs_th = unique_tol(np.concatenate((freqs_th, -freqs_th), axis=0))
Nfreq = freqs_th.size

if Wmatf.size == 0 or If.size == 0:
Expand Down
208 changes: 208 additions & 0 deletions SciDataTool/Functions/set_routines.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import numpy as np


def union1d_tol(ar1, ar2, tol=1e-6, is_abs_tol=False, return_indices=False):
"""Return the intersect1d values of the input array a given tolerance tol
Parameters
----------
ar1 : ndarray
First array to union values
ar2 : ndarray
Second array to union values
tol : Float
the tolerance value
is_abs_tol : bool
True to apply absolute tolerance regarding maximum absolute value in (ar1, ar2)
return_indices : bool
True to return indices
Returns
-------
b : ndarray
array containing unioned values
Ia : ndarray
index array such as ar1 = b[Ia]
Ib : ndarray
index array such as ar2 = b[Ib]
"""

# Get union values as unique values in both arrays
b = unique_tol(
np.concatenate((ar1, ar2)),
tol=tol,
is_abs_tol=is_abs_tol,
return_index=False,
return_inverse=False,
)

if return_indices:
# Map union values with values in 1st array
Ia = np.argmin(np.abs(b[:, None] - ar1[None, :]), axis=0)
# Map union values with values in 2nd array
Ib = np.argmin(np.abs(b[:, None] - ar2[None, :]), axis=0)

return b, Ia, Ib

else:
return b


def unique_tol(
a,
tol=1e-6,
is_abs_tol=False,
return_index=False,
return_inverse=False,
return_counts=False,
is_stable=False,
axis=0,
):
"""Return the unique values of the input array a given tolerance tol
Parameters
----------
a : ndarray
the array to calculate unique values
tol : Float
the tolerance value
is_abs_tol : bool
True to apply absolute tolerance regarding maximum absolute value in a
return_index : bool
to return direct index
return_inverse : bool
to return inverse index
return_counts : bool
to return occurences count
is_stable: bool
to return unique array with stable order (not sorted)
axis : int
Axis index on which to calculate unique values
Returns
-------
b : ndarray
array containing unique values
Ia : ndarray
direct index array such as b=a[Ia] if is stable, else b=sort(a[Ia])
Ib: ndarray
inverse index array such as a=b[Ib]
count0: ndarray
array counting occurences for each unique value
"""

if not is_abs_tol:
tol = get_relative_tolerance(a, tol)

res_tuple = np.unique(
np.round(a / tol),
return_index=True,
return_inverse=return_inverse,
return_counts=return_counts,
axis=axis,
)

if is_stable:
Ia = np.sort(res_tuple[1])
else:
Ia = res_tuple[1]

b = a[Ia]

if return_inverse:
Ib = res_tuple[2]

if return_counts:
count0 = res_tuple[3]

if return_index and return_inverse and return_counts:
return b, Ia, Ib, count0
elif return_index and return_inverse:
return b, Ia, Ib
elif return_index and return_counts:
return b, Ia, count0
elif return_inverse and return_counts:
return b, Ib, count0
elif return_index:
return b, Ia
elif return_inverse:
return b, Ib
elif return_counts:
return b, count0
else:
return b


def intersect1d_tol(
ar1, ar2, tol=1e-6, is_abs_tol=False, return_indices=False, assume_unique=False
):
"""Return the intersect1d values of the input array a given tolerance tol
Parameters
----------
ar1 : ndarray
First array to intersect values
ar2 : ndarray
Second array to intersect values
tol : Float
the tolerance value
is_abs_tol : bool
True to consider absolute tolerance, False to consider relative tolerance
return_indices : bool
True to return original indices for both input arrays
assume_unique : bool
True to assume values are unique in both input arrays
Returns
-------
b : ndarray
array containing common values
Ia : ndarray
array of indices such as b = ar1[Ia]
Ib : ndarray
array of indices such as b = ar2[Ib]
"""

if not is_abs_tol:
tol = get_relative_tolerance(ar1, tol)

_, Ia, Ib = np.intersect1d(
np.floor(ar1 / tol),
np.floor(ar2 / tol),
assume_unique=assume_unique,
return_indices=True,
)

b = ar1[Ia]

if return_indices:
return b, Ia, Ib
else:
return b


def get_relative_tolerance(a, atol):
"""Calculate relative tolerance given an array a and an absolute tolerance
Parameters
----------
a : ndarray
array for which to calculate relative tolerance
atol : float
absolute tolerance
Returns
-------
rtol : float
relative tolerance
"""

a_max = np.max(np.abs(a))
if a_max > 0:
rtol = atol * np.max(np.abs(a))

if rtol > 1:
# threshold tol to 1
rtol = 1

return rtol
16 changes: 6 additions & 10 deletions SciDataTool/Functions/sum_convolution.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import numpy as np

from SciDataTool.Functions.unique_tol import unique_tol
from SciDataTool.Functions.set_routines import unique_tol


def get_conv_indices(freqs1, freqs2, f_min, f_max, tol_freq):
Expand Down Expand Up @@ -57,16 +57,15 @@ def get_conv_indices(freqs1, freqs2, f_min, f_max, tol_freq):
I0 = np.logical_and.reduce((freqs >= f_min, freqs <= f_max))

# Keep only unique rows in order array
result = unique_tol(

freqs_un, I1 = unique_tol(
freqs[I0],
return_inverse=True,
return_index=True,
return_index=False,
axis=0,
is_abs_tol=True,
tol=tol_freq,
)
freqs_un = result["b"]
I1 = result["Ib"]

# Find indices of positive frequencies to be kept
I0a = np.where(I0)[0]
Expand Down Expand Up @@ -170,18 +169,15 @@ def get_sum_indices(freqs1, freqs2, tol_freq):
freqs = np.concatenate((freqs1, freqs2), axis=0)

# Get unique orders
res = unique_tol(
freqs_un, I0b = unique_tol(
freqs,
return_index=True,
return_inverse=True,
return_index=False,
axis=0,
is_abs_tol=True,
tol=tol_freq,
)

freqs_un = res["b"]
I0b = res["Ib"]

return freqs_un, I0b


Expand Down
73 changes: 0 additions & 73 deletions SciDataTool/Functions/unique_tol.py

This file was deleted.

2 changes: 1 addition & 1 deletion SciDataTool/Methods/DataFreq/conv.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def conv(

# Fill metadata
if name is None:
name = self.Name
name = self.name
if symbol is None:
symbol = self.symbol
if unit is None:
Expand Down
2 changes: 1 addition & 1 deletion SciDataTool/Methods/DataFreq/sum.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def sum(

# Fill metadata
if name is None:
name = self.Name
name = self.name
if symbol is None:
symbol = self.symbol
if unit is None:
Expand Down
Loading

0 comments on commit 183cfc3

Please sign in to comment.