diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a75a22e..7df3feb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### New features * [Issue 75](https://github.com/MassimoCimmino/pygfunction/issues/75) - New module `media` with properties of brine mixtures. +* [Issue 81](https://github.com/MassimoCimmino/pygfunction/issues/81) - Added functions to find a remove duplicate boreholes. ## Version 1.1.2 (2021-01-21) diff --git a/doc/source/example_custom_bore_field.rst b/doc/source/example_custom_bore_field.rst index e5011c95..61e4f0be 100644 --- a/doc/source/example_custom_bore_field.rst +++ b/doc/source/example_custom_bore_field.rst @@ -8,6 +8,10 @@ This example demonstrates the use of the :doc:`borehole ` module to define the positions of the boreholes within a bore field from a list of borehole positions. +Two borehole positions (1 and 2) are intentionally added as duplicates and +are removed by calling the :func:`pygfunction.boreholes.remove_duplicates` +function. + The following script generates a bore field with 5 boreholes. The field is then plotted on a figure. diff --git a/pygfunction/boreholes.py b/pygfunction/boreholes.py index 291e3424..b5e51ca6 100644 --- a/pygfunction/boreholes.py +++ b/pygfunction/boreholes.py @@ -101,6 +101,96 @@ def position(self): return pos +def find_duplicates(boreField, disp=False): + """ + The distance method :func:`Borehole.distance` is utilized to find all + duplicate boreholes in a boreField. + This function considers a duplicate to be any pair of points that fall + within each others radius. The lower index (i) is always stored in the + 0 position of the tuple, while the higher index (j) is stored in the 1 + position. + + Parameters + ---------- + boreField : list + A list of :class:`Borehole` objects + disp : bool, optional + Set to true to print progression messages. + Default is False. + + Returns + ------- + duplicate_pairs : list + A list of tuples where the tuples are pairs of duplicates + """ + + duplicate_pairs = [] # define an empty list to be appended to + for i in range(len(boreField)): + borehole_1 = boreField[i] + for j in range(i, len(boreField)): # only loop unique interactions + borehole_2 = boreField[j] + if i == j: # skip the borehole itself + continue + else: + dist = borehole_1.distance(borehole_2) + if abs(dist - borehole_1.r_b) < borehole_1.r_b: + duplicate_pairs.append((i, j)) + if disp: + # pad with '-' align in center + output = f"{ '*gt.boreholes.find_duplicates()*' :-^50}" + # keep a space between the function name + print(output.replace('*', ' ')) + print('The duplicate pairs of boreholes found: {}'\ + .format(duplicate_pairs)) + return duplicate_pairs + + +def remove_duplicates(boreField, disp=False): + """ + Removes all of the duplicates found from the duplicate pairs returned in + :func:`check_duplicates`. + + For each pair of duplicates, the first borehole (with the lower index) is + kept and the other (with the higher index) is removed. + + Parameters + ---------- + boreField : list + A list of :class:`Borehole` objects + disp : bool, optional + Set to true to print progression messages. + Default is False. + + Returns + ------- + new_boreField : list + A boreField without duplicates + """ + # get a list of tuple + duplicate_pairs = find_duplicates(boreField, disp=disp) + + new_boreField = [] + + # values not to be included + duplicate_bores = [] + for i in range(len(duplicate_pairs)): + duplicate_bores.append(duplicate_pairs[i][1]) + + for i in range(len(boreField)): + if i in duplicate_bores: + continue + else: + new_boreField.append(boreField[i]) + if disp: + # pad with '-' align in center + print(f"{'*gt.boreholes.remove_duplicates()*' :-^50}".\ + replace('*', ' ')) # keep a space between the function name + n_duplicates = len(boreField) - len(new_boreField) + print('The number of duplicates removed: {}'.format(n_duplicates)) + + return new_boreField + + def rectangle_field(N_1, N_2, B_1, B_2, H, D, r_b): """ Build a list of boreholes in a rectangular bore field configuration. diff --git a/pygfunction/examples/custom_bore_field.py b/pygfunction/examples/custom_bore_field.py index 629a4061..74e0e0bd 100644 --- a/pygfunction/examples/custom_bore_field.py +++ b/pygfunction/examples/custom_bore_field.py @@ -18,7 +18,13 @@ def main(): r_b = 0.075 # Borehole radius (m) # Borehole positions + # Note: Two duplicate boreholes have been added to this list of positions. + # Position 1 has a borehole that is directly on top of another bore + # Position 2 has a borehole with radius inside of another bore + # The duplicates will be removed with the remove_duplicates function pos = [(0.0, 0.0), + (0.0, 0.0), # Duplicate (for example purposes) + (0.03, 0.0), # Duplicate (for example purposes) (5.0, 0.), (3.5, 4.0), (1.0, 7.0), @@ -31,6 +37,12 @@ def main(): # Build list of boreholes field = [gt.boreholes.Borehole(H, D, r_b, x, y) for (x, y) in pos] + # ------------------------------------------------------------------------- + # Find and remove duplicates from borehole field + # ------------------------------------------------------------------------- + + field = gt.boreholes.remove_duplicates(field, disp=True) + # ------------------------------------------------------------------------- # Draw bore field # -------------------------------------------------------------------------