Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create filled circular borefield #271

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Version 2.3 (in development)

### New features

* [Issue 276](https://github.com/MassimoCimmino/pygfunction/issues/276) - Added functions to the `boreholes` module for the generation of rectangular fields in a staggered configuration.

### Bug fixes

* [Issue 274](https://github.com/MassimoCimmino/pygfunction/issues/274) - Fixed scalar assignment from ndim-1 array. It is deprecated as of `numpy` version `1.25`. Only ndim-0 arrays can be treated as scalars.
Expand Down
18 changes: 17 additions & 1 deletion examples/regular_bore_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
""" Example of definition of a bore field using pre-defined configurations.

"""
import matplotlib.pyplot as plt

import pygfunction as gt


Expand Down Expand Up @@ -29,6 +31,14 @@ def main():
# Rectangular field of 4 x 3 boreholes
rectangularField = gt.boreholes.rectangle_field(N_1, N_2, B, B, H, D, r_b)

# Rectangular field triangular field of 4 x 3 borehole rows
staggeredRectangularField = gt.boreholes.staggered_rectangle_field(
N_1, N_2, B, B, H, D, r_b, False)

# Dense field triangular field of 4 x 3 borehole rows
denseRectangularField = gt.boreholes.dense_rectangle_field(
N_1, N_2, B, H, D, r_b, False)

# Box-shaped field of 4 x 3 boreholes
boxField = gt.boreholes.box_shaped_field(N_1, N_2, B, B, H, D, r_b)

Expand All @@ -41,11 +51,17 @@ def main():
# Circular field of 8 boreholes
circleField = gt.boreholes.circle_field(N_b, R, H, D, r_b)

# Filled circle field of 20 boreholes
filledCircleField = gt.boreholes.filled_circle_field(20, 10, 100, 1, 0.05)

# -------------------------------------------------------------------------
# Draw bore fields
# -------------------------------------------------------------------------
for field in [rectangularField, boxField, UField, LField, circleField]:
for field in [
rectangularField, staggeredRectangularField, denseRectangularField,
boxField, UField, LField, circleField, filledCircleField]:
gt.boreholes.visualize_field(field)
plt.show()

return

Expand Down
235 changes: 234 additions & 1 deletion pygfunction/boreholes.py
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,176 @@ def rectangle_field(N_1, N_2, B_1, B_2, H, D, r_b, tilt=0., origin=None):
return borefield


def staggered_rectangle_field(
N_1, N_2, B_1, B_2, H, D, r_b, include_last_borehole, tilt=0.,
origin=None):
"""
Build a list of boreholes in a rectangular bore field configuration, with
boreholes placed in a staggered configuration.

Parameters
----------
N_1 : int
Number of borehole in the x direction.
N_2 : int
Number of borehole in the y direction.
B_1 : float
Distance (in meters) between adjacent boreholes in the x direction.
B_2 : float
Distance (in meters) between adjacent boreholes in the y direction.
H : float
Borehole length (in meters).
D : float
Borehole buried depth (in meters).
r_b : float
Borehole radius (in meters).
include_last_borehole : bool
If True, then each row of boreholes has equal numbers of boreholes.
If False, then the staggered rows have one borehole less so they are
contained within the imaginary 'box' around the borefield.
tilt : float, optional
Angle (in radians) from vertical of the axis of the borehole. The
orientation of the tilt is orthogonal to the origin coordinate.
Default is 0.
origin : tuple, optional
A coordinate indicating the origin of reference for orientation of
boreholes.
Default is the center of the rectangle.

Returns
-------
boreField : list of Borehole objects
List of boreholes in the rectangular bore field.

Notes
-----
Boreholes located at the origin will remain vertical.

Examples
--------
>>> boreField = gt.boreholes.rectangle_field(N_1=3, N_2=2, B_1=5., B_2=5.,
H=100., D=2.5, r_b=0.05)

The bore field is constructed line by line. For N_1=3 and N_2=3, the bore
field layout is as follows, if `include_last_borehole` is True::

6 7 8
3 4 5
0 1 2

and if `include_last_borehole` is False::

5 6 7
3 4
0 1 2

"""
borefield = []

if N_1 == 1 or N_2 == 1:
return rectangle_field(N_1, N_2, B_1, B_2, H, D, r_b, tilt, origin)

if origin is None:
# When no origin is supplied, compute the origin to be at the center of
# the rectangle
if include_last_borehole:
x0 = (N_1 - 1) / 2 * B_1
y0 = (N_2 - 1) / 2 * B_2
else:
x0 = (N_1 - 0.5) / 2 * B_1
y0 = (N_2 - 0.5) / 2 * B_2
else:
x0, y0 = origin

for j in range(N_2):
for i in range(N_1):
x = i * B_1 + (B_1 / 2 if j % 2 == 1 else 0)
y = j * B_2
# The borehole is inclined only if it does not lie on the origin
if np.sqrt((x - x0)**2 + (y - y0)**2) > r_b:
orientation = np.arctan2(y - y0, x - x0)
if i < (N_1 - 1) or include_last_borehole or (j % 2 == 0):
borefield.append(
Borehole(
H, D, r_b, x, y, tilt=tilt, orientation=orientation))
else:
if i < (N_1 - 1) or include_last_borehole or (j % 2 == 0):
borefield.append(Borehole(H, D, r_b, x, y))

return borefield


def dense_rectangle_field(
N_1, N_2, B, H, D, r_b, include_last_borehole, tilt=0., origin=None):
"""
Build a list of boreholes in a rectangular bore field configuration, with
boreholes placed in a staggered configuration with uniform spacing between
boreholes.

Parameters
----------
N_1 : int
Number of borehole in the x direction.
N_2 : int
Number of borehole in the y direction.
B : float
Distance (in meters) between adjacent boreholes.
H : float
Borehole length (in meters).
D : float
Borehole buried depth (in meters).
r_b : float
Borehole radius (in meters).
include_last_borehole : bool
If True, then each row of boreholes has equal numbers of boreholes.
If False, then the staggered rows have one borehole less so they are
contained within the imaginary 'box' around the borefield.
tilt : float, optional
Angle (in radians) from vertical of the axis of the borehole. The
orientation of the tilt is orthogonal to the origin coordinate.
Default is 0.
origin : tuple, optional
A coordinate indicating the origin of reference for orientation of
boreholes.
Default is the center of the rectangle.

Returns
-------
boreField : list of Borehole objects
List of boreholes in the rectangular bore field.

Notes
-----
Boreholes located at the origin will remain vertical.

Examples
--------
>>> boreField = gt.boreholes.rectangle_field(
N_1=3, N_2=2, B_1=5., B_2=5., H=100., D=2.5, r_b=0.05,
include_last_borehole=True)

The bore field is constructed line by line. For N_1=3 and N_2=3, the bore
field layout is as follows, if `include_last_borehole` is True::

6 7 8
3 4 5
0 1 2

and if `include_last_borehole` is False::

5 6 7
3 4
0 1 2

"""
if N_1 == 1:
# line field
return rectangle_field(N_1, N_2, B, B, H, D, r_b, tilt, origin)
return staggered_rectangle_field(
N_1, N_2, B, np.sqrt(3)/2 * B, H, D, r_b, include_last_borehole,
tilt=tilt, origin=origin)


def L_shaped_field(N_1, N_2, B_1, B_2, H, D, r_b, tilt=0., origin=None):
"""
Build a list of boreholes in a L-shaped bore field configuration.
Expand Down Expand Up @@ -1078,7 +1248,6 @@ def circle_field(N, R, H, D, r_b, tilt=0., origin=None):
for i in range(N):
x = R * np.cos(2 * pi * i / N)
y = R * np.sin(2 * pi * i / N)
orientation = np.arctan2(y - y0, x - x0)
# The borehole is inclined only if it does not lie on the origin
if np.sqrt((x - x0)**2 + (y - y0)**2) > r_b:
orientation = np.arctan2(y - y0, x - x0)
Expand All @@ -1091,6 +1260,70 @@ def circle_field(N, R, H, D, r_b, tilt=0., origin=None):
return borefield


def filled_circle_field(N, B, H, D, r_b, tilt=0., origin=None):
"""
Build a list of boreholes in a filled circular configuration, starting from the origin
and spiralling outside.

Parameters
----------
N : int
Number of boreholes in the bore field.
B : float
Distance between consecutive circles of boreholes (in meters).
H : float
Borehole length (in meters).
D : float
Borehole buried depth (in meters).
r_b : float
Borehole radius (in meters).
tilt : float, optional
Angle (in radians) from vertical of the axis of the borehole. The
orientation of the tilt is towards the exterior of the bore field.
Default is 0.
origin : tuple
A coordinate indicating the origin of reference for orientation of
boreholes.
Default is the origin (0, 0).

Returns
-------
boreField : list of Borehole objects
List of boreholes in the filled circle shaped bore field.

Notes
-----
Boreholes located at the origin will remain vertical.
"""

if origin is None:
# When no origin is supplied, compute the origin to be at the center of
# the rectangle
x0 = 0.
y0 = 0.
else:
x0, y0 = origin

field = [Borehole(H, D, r_b, 0, 0)]
a = 6 # number of boreholes in a circle, 6 for the inner circle
B2 = B # radius of the borehole
counter = 0

for i in range(N - 1):
i = i + 1
counter = counter + 1
if counter > a:
a = a + 6
B2 = B2 + B
counter = 1
# The borehole is inclined only if it does not lie on the origin, which is always the case
x, y = B2 * np.sin(2 * np.pi * counter / a), B2 * np.cos(2 * np.pi * counter / a)
orientation = np.arctan2(y - y0, x - x0)
field.append(Borehole(H, D, r_b, x, y, tilt=tilt, orientation=orientation))

return field


def field_from_file(filename):
"""
Build a list of boreholes given coordinates and dimensions provided in a
Expand Down
Loading