Skip to content

Commit

Permalink
Merge branch 'master' into ls-v1.6
Browse files Browse the repository at this point in the history
  • Loading branch information
lachlangrose authored May 29, 2024
2 parents b3bdcd7 + 5bcfc07 commit 0b0836e
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 34 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ jobs:
documentation-deploy:
runs-on: ubuntu-latest
needs: release-please
# if: ${{ needs.release-please.outputs.release_created }}
if: ${{ needs.release-please.outputs.release_created }}
steps:
- uses: actions/checkout@v4
- run: |
Expand All @@ -92,7 +92,7 @@ jobs:
folder: docs/build/html # The folder the action should deploy.

conda-deploy:
name: Uploading to Loop3d for python ${{ matrix.os }})
name: Building conda package for python ${{ matrix.os }})
needs: ["documentation-test", "continuous-integration"]
runs-on: ${{matrix.os}}
strategy:
Expand Down
21 changes: 12 additions & 9 deletions LoopStructural/datatypes/_bounding_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def __init__(
global_origin: Optional[np.ndarray] = None,
nsteps: Optional[np.ndarray] = None,
step_vector: Optional[np.ndarray] = None,
dimensions: int = 3,
dimensions: Optional[int] = None,
):
"""A bounding box for a model, defined by the
origin, maximum and number of steps in each direction
Expand All @@ -40,14 +40,16 @@ def __init__(
global_origin = origin
self._origin = np.array(origin)
self._maximum = np.array(maximum)
if global_origin is None:
global_origin = np.zeros(3)

self._global_origin = global_origin
self.dimensions = dimensions
self.nsteps = np.array([50, 50, 25])
if nsteps is not None:
self.nsteps = np.array(nsteps)
if dimensions is None:
if self.origin is None:
raise LoopValueError("Origin is not set")
self.dimensions = len(self.origin)
print(self.dimensions)
else:
self.dimensions = dimensions
if nsteps is None:
self.nsteps = np.array([50, 50, 25])
self.name_map = {
"xmin": (0, 0),
"ymin": (0, 1),
Expand Down Expand Up @@ -128,7 +130,7 @@ def nelements(self, nelements: Union[int, float]):
box_vol = self.volume
ele_vol = box_vol / nelements
# calculate the step vector of a regular cube
step_vector = np.zeros(3)
step_vector = np.zeros(self.dimensions)
step_vector[:] = ele_vol ** (1.0 / 3.0)
# number of steps is the length of the box / step vector
nsteps = np.ceil((self.maximum - self.origin) / step_vector).astype(int)
Expand Down Expand Up @@ -327,6 +329,7 @@ def regular_grid(
locs = np.array(
[xx.flatten(order=order), yy.flatten(order=order), zz.flatten(order=order)]
).T

if shuffle:
# logger.info("Shuffling points")
rng.shuffle(locs)
Expand Down
32 changes: 10 additions & 22 deletions LoopStructural/export/exporters.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ def write_feat_surfs(
logger.warning("{featurename} is not in the model, skipping")
return False, []
has_feats = True
x = np.linspace(model.bounding_box[0, 0], model.bounding_box[1, 0], model.nsteps[0])
y = np.linspace(model.bounding_box[0, 1], model.bounding_box[1, 1], model.nsteps[1])
z = np.linspace(model.bounding_box[1, 2], model.bounding_box[0, 2], model.nsteps[2])

x = np.linspace(model.bounding_box.bb[0, 0], model.bounding_box.bb[1, 0], model.nsteps[0])
y = np.linspace(model.bounding_box.bb[0, 1], model.bounding_box.bb[1, 1], model.nsteps[1])
z = np.linspace(model.bounding_box.bb[1, 2], model.bounding_box.bb[0, 2], model.nsteps[2])
xx, yy, zz = np.meshgrid(x, y, z, indexing="ij")
points = np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T
val = model[featurename].evaluate_value(points)
Expand All @@ -82,9 +83,9 @@ def write_feat_surfs(
)
verts += np.array(
[
model.bounding_box[0, 0],
model.bounding_box[0, 1],
model.bounding_box[1, 2],
model.bounding_box.bb[0, 0],
model.bounding_box.bb[0, 1],
model.bounding_box.bb[1, 2],
]
)
model.rescale(verts)
Expand Down Expand Up @@ -422,14 +423,7 @@ def _write_vol_evtk(model, file_name, data_label, nsteps, real_coords=True):
"""
# Define grid spacing
loop_X = np.linspace(model.bounding_box[0, 0], model.bounding_box[1, 0], nsteps[0])
loop_Y = np.linspace(model.bounding_box[0, 1], model.bounding_box[1, 1], nsteps[1])
loop_Z = np.linspace(model.bounding_box[0, 2], model.bounding_box[1, 2], nsteps[2])

# Generate model values in 3d grid
xx, yy, zz = np.meshgrid(loop_X, loop_Y, loop_Z, indexing="ij")
# xyz is N x 3 vector array
xyz = np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T
xyz = model.bounding_box.regular_grid(nsteps)
vals = model.evaluate_model(xyz, scale=False)
if real_coords:
model.rescale(xyz)
Expand Down Expand Up @@ -471,14 +465,8 @@ def _write_vol_gocad(model, file_name, data_label, nsteps, real_coords=True):
"""
# Define grid spacing in model scale coords
loop_X = np.linspace(model.bounding_box[0, 0], model.bounding_box[1, 0], nsteps[0])
loop_Y = np.linspace(model.bounding_box[0, 1], model.bounding_box[1, 1], nsteps[1])
loop_Z = np.linspace(model.bounding_box[0, 2], model.bounding_box[1, 2], nsteps[2])

# Generate model values in 3d grid
xx, yy, zz = np.meshgrid(loop_X, loop_Y, loop_Z, indexing="ij")
# xyz is N x 3 vector array
xyz = np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T
xyz = model.bounding_box.regular_grid(nsteps)

vals = model.evaluate_model(xyz, scale=False)
# Use FORTRAN style indexing for GOCAD VOXET
vol_vals = np.reshape(vals, nsteps, order="F")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ def install_gradient_constraint(self):
vector[norm > 0] /= norm[norm > 0, None]
element_idx = np.arange(self.interpolator.support.n_elements)
logger.info(f"Adding to least squares matrix: {self.name}")

self.interpolator.add_gradient_orthogonal_constraints(
self.interpolator.support.barycentre[element_idx[::step], :],
vector[element_idx[::step], :],
Expand Down
5 changes: 5 additions & 0 deletions LoopStructural/utils/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ def gi(i, j):


def create_box(bounding_box, nsteps):
from LoopStructural.datatypes import BoundingBox

if isinstance(bounding_box, BoundingBox):
bounding_box = bounding_box.bb

tri, xx, yy = create_surface(bounding_box[0:2, :], nsteps[0:2])

zz = np.zeros(xx.shape)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,24 @@ def test_create_bounding_box():
assert bbox.maximum[0] == 1
assert bbox.maximum[1] == 1
assert bbox.maximum[2] == 1
assert bbox.dimensions == 3
assert np.all(bbox.bb == np.array([[0, 0, 0], [1, 1, 1]]))
assert bbox.valid is True


def test_create_bounding_box_2d():
bbox = BoundingBox(origin=[0, 0], maximum=[1, 1], dimensions=2)
assert bbox.origin[0] == 0
assert bbox.origin[1] == 0
assert bbox.maximum[0] == 1
assert bbox.maximum[1] == 1
assert bbox.dimensions == 2
assert np.all(bbox.bb == np.array([[0, 0], [1, 1]]))
assert bbox.valid is True


def test_create_bounding_box_from_points():
bbox = BoundingBox()
bbox = BoundingBox(dimensions=3)
bbox.fit(np.array([[0, 0, 0], [1, 1, 1]]))
assert bbox.origin[0] == 0
assert bbox.origin[1] == 0
Expand All @@ -27,6 +39,27 @@ def test_create_bounding_box_from_points():
assert bbox.valid is True


def test_create_bounding_box_from_points_2d():
bbox = BoundingBox(dimensions=2)
bbox.fit(np.array([[0, 0], [1, 1]]))
assert bbox.origin[0] == 0
assert bbox.origin[1] == 0
assert bbox.maximum[0] == 1
assert bbox.maximum[1] == 1
assert np.all(bbox.bb == np.array([[0, 0], [1, 1]]))
assert bbox.valid is True


def test_create_3d_bounding_box_from_2d_points():
bbox = BoundingBox(dimensions=3)
try:
bbox.fit(np.array([[0, 0], [1, 1]]))
except Exception as e:
assert str(e) == "locations array is 2D but bounding box is 3"
else:
assert False


def test_create_with_buffer():
bbox = BoundingBox(origin=[0, 0, 0], maximum=[1, 1, 1])
bbox = bbox.with_buffer(0.2)
Expand All @@ -51,8 +84,24 @@ def test_is_inside():
assert not np.all(bbox.is_inside(np.array([-0.5, 0.5, 0.5])))


def test_regular_grid_3d():
bbox = BoundingBox(origin=[0, 0, 0], maximum=[1, 1, 1])
print(bbox.dimensions)
grid = bbox.regular_grid((10, 10, 10))
assert grid.shape == (10 * 10 * 10, 3)


def test_regular_grid_2d():
bbox = BoundingBox(origin=[0, 0], maximum=[1, 1], dimensions=2)
print(bbox.dimensions)
grid = bbox.regular_grid((10, 10))
assert grid.shape == (10 * 10, 2)


if __name__ == "__main__":
test_create_bounding_box()
test_create_bounding_box_from_points()
test_create_with_buffer()
test_is_inside()
test_regular_grid_3d()
test_regular_grid_2d()

0 comments on commit 0b0836e

Please sign in to comment.