Skip to content

Commit

Permalink
Merge branch 'v1.0' of https://github.com/Loop3D/foldoptlib into v1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
rabii-chaarani committed May 21, 2024
2 parents 31b21c8 + 4b16561 commit 8c686be
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 29 deletions.
23 changes: 15 additions & 8 deletions FoldOptLib/fold_modelling/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from ..from_loopstructural._fold_frame import FoldFrame
from .base_engine import BaseEngine
from ..optimisers import FourierSeriesOptimiser
from LoopStructural.utils._transformation import EuclideanTransformation
import gc


Expand Down Expand Up @@ -114,7 +113,9 @@ def initialise_model(self) -> None:
self.points
) # EuclideanTransformation(dimensions=self.dimensions).fit_transform(self.points)

def process_axial_surface_proposition(self, axial_normal: numpy.ndarray) -> pandas.DataFrame:
def process_axial_surface_proposition(
self, axial_normal: numpy.ndarray
) -> pandas.DataFrame:
"""
Process the axial surface proposition at each iteration by creating a dataset from the axial surface normal.
Expand Down Expand Up @@ -194,9 +195,9 @@ def create_and_build_fold_event(self) -> FoldEvent:
foldframe = FoldFrame("sn", self.axial_surface)

# calculate the gradient of the axial surface
s1g = self.axial_surface[CoordinateType.AXIAL_FOLIATION_FIELD].evaluate_gradient(
self.scaled_points
)
s1g = self.axial_surface[
CoordinateType.AXIAL_FOLIATION_FIELD
].evaluate_gradient(self.scaled_points)

# normalise the gradient
s1g /= numpy.linalg.norm(s1g, axis=1)[:, None]
Expand Down Expand Up @@ -242,7 +243,9 @@ def create_and_build_fold_event(self) -> FoldEvent:
fold_axis_rotation_function = fold_function(fitted_far)

# create a fold event with the axial surface and fold axis rotation function
fold = FoldEvent(self.axial_surface, fold_axis_rotation=fold_axis_rotation_function)
fold = FoldEvent(
self.axial_surface, fold_axis_rotation=fold_axis_rotation_function
)

# calculate the fold limb rotation angle
flr, fld = foldframe.calculate_fold_limb_rotation(
Expand Down Expand Up @@ -371,7 +374,9 @@ def fit_fourier_series(
return opt.x

else:
fourier_optimiser = FourierSeriesOptimiser(fold_frame_coordinate, rotation_angle, x)
fourier_optimiser = FourierSeriesOptimiser(
fold_frame_coordinate, rotation_angle, x
)
# Optimise the Fourier series
opt = fourier_optimiser.optimise()

Expand All @@ -395,7 +400,9 @@ def calculate_folded_foliation_vectors(self) -> numpy.ndarray:
s1g /= numpy.linalg.norm(s1g, axis=1)[:, None]

# Get deformed orientation and normalize the fold direction
fold_direction, fold_axis, gz = fold.get_deformed_orientation(self.scaled_points)
fold_direction, fold_axis, gz = fold.get_deformed_orientation(
self.scaled_points
)
fold_direction /= numpy.linalg.norm(fold_direction, axis=1)[:, None]

# Correct any fold_direction vector to be consistent with the axial surface orientation
Expand Down
22 changes: 16 additions & 6 deletions FoldOptLib/input/data_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,14 @@ def set_axial_surface_field_constraints(self):
mean_x, mean_y, mean_z = self.axial_normals()[["X", "Y", "Z"]].mean(0)
min_x, min_y, min_z = self.axial_normals()[["X", "Y", "Z"]].min(0)
max_x, max_y, max_z = self.axial_normals()[["X", "Y", "Z"]].max(0)
value_constraints = numpy.array([[mean_x, mean_y, mean_z, 0.0, 1.0],
[min_x, min_y, min_z, -1.0, 1.0],
[max_x, max_y, max_z, 1.0, 1.0]], dtype=float)
value_constraints = numpy.array(
[
[mean_x, mean_y, mean_z, 0.0, 1.0],
[min_x, min_y, min_z, -1.0, 1.0],
[max_x, max_y, max_z, 1.0, 1.0],
],
dtype=float,
)

normal_constraints = self.axial_normals()[
["X", "Y", "Z", "gx", "gy", "gz", "weight"]
Expand All @@ -163,9 +168,14 @@ def set_fold_axis_field_constraints(self):
mean_x, mean_y, mean_z = self.y_normals()[["X", "Y", "Z"]].mean(0)
min_x, min_y, min_z = self.y_normals()[["X", "Y", "Z"]].min(0)
max_x, max_y, max_z = self.y_normals()[["X", "Y", "Z"]].max(0)
value_constraints = numpy.array([[mean_x, mean_y, mean_z, 0.0, 1.0],
[min_x, min_y, min_z, -1.0, 1.0],
[max_x, max_y, max_z, 1.0, 1.0]], dtype=float)
value_constraints = numpy.array(
[
[mean_x, mean_y, mean_z, 0.0, 1.0],
[min_x, min_y, min_z, -1.0, 1.0],
[max_x, max_y, max_z, 1.0, 1.0],
],
dtype=float,
)

normal_constraints = self.y_normals()[
["X", "Y", "Z", "gx", "gy", "gz", "weight"]
Expand Down
1 change: 0 additions & 1 deletion FoldOptLib/input/input_data_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ def __post_init__(self):
else:
raise ValueError("Data must be a pandas DataFrame.")


@staticmethod
def normalise(gradient: numpy.ndarray) -> numpy.ndarray:
"""Normalise vectors."""
Expand Down
53 changes: 39 additions & 14 deletions tests/unit/fold_model/test_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@
from FoldOptLib.builders import FoldFrameBuilder, Builder
from LoopStructural import BoundingBox


# Sample data for tests
@pytest.fixture
def sample_data():
data = {
"gx": [0., 0., 0.],
"gy": [0., 0.5, 0.1],
"gx": [0.0, 0.0, 0.0],
"gy": [0.0, 0.5, 0.1],
"gz": [0.5, 0.4, 0.5],
"X": [10, 11, 12],
"Y": [13, 14, 15],
"Z": [16, 17, 18],
"Z": [16, 17, 18],
"feature_name": ["feature", "feature", "feature"],
"weight": [1, 1, 1],
}
Expand All @@ -26,52 +27,76 @@ def sample_data():

return input_data


@pytest.fixture
def fold_model(sample_data):
return FoldModel(sample_data)


def test_initialization(fold_model, sample_data):
assert fold_model.raw_data is sample_data
assert fold_model.bounding_box is sample_data[DataType.BOUNDING_BOX]
assert fold_model.model is None
# Ensure the columns are present
assert 'weight' in sample_data[DataType.DATA].columns, "'weight' column is missing from sample_data"
np.testing.assert_array_equal(fold_model.gradient_data, sample_data[DataType.DATA][["gx", "gy", "gz"]].to_numpy())
np.testing.assert_array_equal(fold_model.points, sample_data[DataType.DATA][["X", "Y", "Z"]].to_numpy())
assert (
"weight" in sample_data[DataType.DATA].columns
), "'weight' column is missing from sample_data"
np.testing.assert_array_equal(
fold_model.gradient_data,
sample_data[DataType.DATA][["gx", "gy", "gz"]].to_numpy(),
)
np.testing.assert_array_equal(
fold_model.points, sample_data[DataType.DATA][["X", "Y", "Z"]].to_numpy()
)
assert fold_model.axial_surface is None
assert fold_model.scaled_points is None


def test_set_data(fold_model, sample_data):

fold_model.set_data(sample_data)
np.testing.assert_array_equal(fold_model.data[["gx"]], sample_data[DataType.DATA][["gx"]])
np.testing.assert_array_equal(
fold_model.data[["gx"]], sample_data[DataType.DATA][["gx"]]
)


def test_initialise_model(fold_model):
fold_model.initialise_model()
assert fold_model.data is not None
assert fold_model.scaled_points is not None
assert fold_model.geological_knowledge is None


def test_process_axial_surface_proposition(fold_model, sample_data):
fold_model.initialise_model()
axial_normal = np.array([1., 0., 0.], dtype=float)
np.testing.assert_array_equal(fold_model.points, sample_data[DataType.DATA][["X", "Y", "Z"]].to_numpy())
axial_normal = np.array([1.0, 0.0, 0.0], dtype=float)
np.testing.assert_array_equal(
fold_model.points, sample_data[DataType.DATA][["X", "Y", "Z"]].to_numpy()
)
result = fold_model.process_axial_surface_proposition(axial_normal)
assert isinstance(result, OptData)


def test_build_fold_frame(fold_model, sample_data):
fold_model.initialise_model()
# Ensure the columns are present
assert 'weight' in fold_model.raw_data[DataType.DATA].columns, "'weight' column is missing from sample_data"
axial_normal = np.array([1., 0., 0.], dtype=float)
np.testing.assert_array_equal(fold_model.points, sample_data[DataType.DATA][["X", "Y", "Z"]].to_numpy())
assert (
"weight" in fold_model.raw_data[DataType.DATA].columns
), "'weight' column is missing from sample_data"
axial_normal = np.array([1.0, 0.0, 0.0], dtype=float)
np.testing.assert_array_equal(
fold_model.points, sample_data[DataType.DATA][["X", "Y", "Z"]].to_numpy()
)
result = fold_model.process_axial_surface_proposition(axial_normal)
assert isinstance(result, OptData)
fold_model.build_fold_frame(axial_normal)
assert isinstance(fold_model.axial_surface, FoldFrameBuilder)
assert isinstance(fold_model.axial_surface[CoordinateType.AXIAL_FOLIATION_FIELD], Builder)
assert isinstance(
fold_model.axial_surface[CoordinateType.AXIAL_FOLIATION_FIELD], Builder
)
assert isinstance(fold_model.axial_surface[CoordinateType.FOLD_AXIS_FIELD], Builder)


# def test_create_and_build_fold_event(fold_model):
# fold_model.initialise_model()
# axial_normal = np.array([1., 0., 0.], dtype=float)
Expand Down

0 comments on commit 8c686be

Please sign in to comment.