diff --git a/FoldOptLib/builders/fold_frame_builder.py b/FoldOptLib/builders/fold_frame_builder.py index 6a31187..9f8206f 100644 --- a/FoldOptLib/builders/fold_frame_builder.py +++ b/FoldOptLib/builders/fold_frame_builder.py @@ -1,19 +1,24 @@ -from .structural_frame_builder import StructuralFrameBuilder -from ..datatypes import ConstraintType, InterpolationConstraints +from .structural_frame_builder import Builder +from ..input import OptData +from ..datatypes import CoordinateType, InterpolationConstraints from LoopStructural import LoopInterpolator, BoundingBox import numpy -class FoldFrameBuilder(StructuralFrameBuilder): +class FoldFrameBuilder(Builder): - def __init__(self, constraints: InterpolationConstraints, bounding_box: BoundingBox): + def __init__(self, constraints: OptData, bounding_box: BoundingBox): super().__init__(constraints, bounding_box) def build_axial_surface_field(self): - pass + + self.set_constraints() def build_fold_axis_field(self): pass def build_x_axis_field(self): pass + + def build(self): + pass diff --git a/FoldOptLib/builders/structural_frame_builder.py b/FoldOptLib/builders/structural_frame_builder.py index e2f7b69..d4e2605 100644 --- a/FoldOptLib/builders/structural_frame_builder.py +++ b/FoldOptLib/builders/structural_frame_builder.py @@ -1,12 +1,14 @@ from base_builder import BaseBuilder -from ..datatypes import ConstraintType, InterpolationConstraints +from ..input import OptData +from ..datatypes import CoordinateType, InterpolationConstraints from LoopStructural import LoopInterpolator, BoundingBox import numpy +from typing import Union, Any -class StructuralFrameBuilder(BaseBuilder): +class Builder(BaseBuilder): - def __init__(self, constraints: InterpolationConstraints, bounding_box: BoundingBox): + def __init__(self, constraints: Union[InterpolationConstraints, OptData], bounding_box: BoundingBox): self.constraints = constraints self.bounding_box = bounding_box self.interpolator = LoopInterpolator( @@ -14,13 +16,14 @@ def __init__(self, constraints: InterpolationConstraints, bounding_box: Bounding dimensions=3, nelements=1000 ) - - def set_constraints(self): - self.interpolator.fit( - values=self.constraints[ConstraintType.VALUE], - tangent_vectors=self.constraints[ConstraintType.TANGENT], - normal_vectors=self.constraints[ConstraintType.NORMAL], - ) + #TODO:Restart from here + + # def set_constraints(self, type: Union[CoordinateType, Any]): + # self.interpolator.fit( + # values=self.constraints[type.VALUE], + # tangent_vectors=self.constraints[type.TANGENT], + # normal_vectors=self.constraints[type.NORMAL], + # ) def evaluate_scalar_value(self, locations: numpy.ndarray) -> numpy.ndarray: return self.interpolator.evaluate_scalar_value(locations) diff --git a/FoldOptLib/datatypes/__init__.py b/FoldOptLib/datatypes/__init__.py index 18cd47b..73f9518 100644 --- a/FoldOptLib/datatypes/__init__.py +++ b/FoldOptLib/datatypes/__init__.py @@ -1,4 +1,4 @@ from .probability_distributions import NormalDistribution, VonMisesFisherDistribution from .input_geological_knowledge import InputGeologicalKnowledge -from .enums import KnowledgeType, OptimisationType, ObjectiveType, DataType, SolverType, ConstraintType +from .enums import * from .interpolation_constraints import InterpolationConstraints diff --git a/FoldOptLib/datatypes/enums.py b/FoldOptLib/datatypes/enums.py index 9c087bc..89a18e7 100644 --- a/FoldOptLib/datatypes/enums.py +++ b/FoldOptLib/datatypes/enums.py @@ -45,7 +45,7 @@ class RotationType(IntEnum): AXIS = 1 -class ConstraintType(IntEnum): +class CoordinateType(IntEnum): VALUE = 0 TANGENT = 1 NORMAL = 2 diff --git a/FoldOptLib/datatypes/interpolation_constraints.py b/FoldOptLib/datatypes/interpolation_constraints.py index 82c4bb5..fd0693c 100644 --- a/FoldOptLib/datatypes/interpolation_constraints.py +++ b/FoldOptLib/datatypes/interpolation_constraints.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from typing import Union, Optional -from enums import ConstraintType +from enums import CoordinateType import numpy import beartype @@ -28,11 +28,11 @@ class InterpolationConstraints: gradient_constraints: Optional[Union[list, numpy.ndarray]] = None @beartype.beartype - def __getitem__(self, constraint_type: ConstraintType): + def __getitem__(self, constraint_type: CoordinateType): constraints = { - ConstraintType.VALUE: self.value_constraints, - ConstraintType.TANGENT: self.tangent_constraints, - ConstraintType.NORMAL: self.normal_constraints, - ConstraintType.GRADIENT: self.gradient_constraints + CoordinateType.VALUE: self.value_constraints, + CoordinateType.TANGENT: self.tangent_constraints, + CoordinateType.NORMAL: self.normal_constraints, + CoordinateType.GRADIENT: self.gradient_constraints } return constraints[constraint_type] diff --git a/FoldOptLib/fold_modelling/engine.py b/FoldOptLib/fold_modelling/engine.py index 86b9cfe..fc226bd 100644 --- a/FoldOptLib/fold_modelling/engine.py +++ b/FoldOptLib/fold_modelling/engine.py @@ -115,14 +115,14 @@ def process_axial_surface_proposition(self, axial_normal: np.ndarray) -> pd.Data # normalise axial surface normal axial_normal /= np.linalg.norm(axial_normal) # create a dataset from the axial surface normal - dataset = create_dataset(axial_normal, self.points, name='s1', coord=0) + dataset = create_dataset(axial_normal, self.points, name='sn', coord=0) assert len(self.points) == len(self.gradient_data), "coordinates must have the same length as data" # rotate the axial normal by 90 degrees to create the Y axis of the fold frame y = rotate_vector(axial_normal, np.pi / 2, dimension=3) # create a dataset from the Y axis of the fold frame - y_coord = create_dataset(y, self.points, name='s1', coord=1) + y_coord = create_dataset(y, self.points, name='sn', coord=1) # append the two datasets together dataset = pd.concat([dataset, y_coord]) @@ -152,7 +152,7 @@ def build_fold_frame(self, axial_normal: np.ndarray) -> None: self.model.data = dataset # create and add a fold frame to the model - self.axial_surface = self.model.create_and_add_fold_frame('s1', + self.axial_surface = self.model.create_and_add_fold_frame('sn', buffer=0.6, solver='pyamg', nelements=1e3, @@ -177,7 +177,7 @@ def create_and_build_fold_event(self) -> FoldEvent: The created fold event. """ # create a fold frame object from the axial surface - foldframe = FoldFrame('s1', self.axial_surface) + foldframe = FoldFrame('sn', self.axial_surface) # calculate the gradient of the axial surface s1g = self.axial_surface[0].evaluate_gradient(self.scaled_points) diff --git a/FoldOptLib/input/__init__.py b/FoldOptLib/input/__init__.py index 17fe0f4..5b73bf0 100644 --- a/FoldOptLib/input/__init__.py +++ b/FoldOptLib/input/__init__.py @@ -1,2 +1,3 @@ from .input_data_checker import CheckInputData from .input_data_processor import InputDataProcessor +from .data_storage import InputData, OptData diff --git a/FoldOptLib/input/data_storage.py b/FoldOptLib/input/data_storage.py index 126d3a1..6eec1c3 100644 --- a/FoldOptLib/input/data_storage.py +++ b/FoldOptLib/input/data_storage.py @@ -1,10 +1,11 @@ -from dataclasses import dataclass -from ..datatypes import KnowledgeType, DataType, InputGeologicalKnowledge +from dataclasses import dataclass, field +from ..datatypes import KnowledgeType, DataType, InputGeologicalKnowledge, CoordinateType, InterpolationConstraints, CoordinateType from ..objective_functions import GeologicalKnowledgeFunctions from LoopStructural import BoundingBox import pandas import numpy import beartype +from typing import List @dataclass class InputData: @@ -22,10 +23,11 @@ def foliations(self): def number_of_foliations(self): return len(self.foliations()) - def get_foliations(self, feature_name): + @beartype.beartype + def get_foliations(self, feature_name: str): return self.data[self.data['feature_name'] == feature_name] - + @beartype.beartype def __getitem__(self, data_type: DataType): data_map = { @@ -36,4 +38,158 @@ def __getitem__(self, data_type: DataType): return data_map[data_type] + + +@beartype.beartype +@dataclass +class OptData: + """ + Class representing optimisation data. + + Attributes + ---------- + data : pandas.DataFrame + The input data. + constraints : List[InterpolationConstraints] + The interpolation constraints. + + Methods + ------- + set_constraints(constraints: InterpolationConstraints, constraint_type: ConstraintType): + Set the interpolation constraints for a given constraint type. + axial_normals(): + Get the axial normals from the data. + y_normals(): + Get the y normals from the data. + set_axial_surface_field_constraints(): + Set the axial surface field constraints. + set_fold_axis_field_constraints(): + Set the fold axis field constraints. + _getitem__(constraint_type: ConstraintType): + Get the interpolation constraints for a given constraint type. + """ + data : pandas.DataFrame + constraints: List[InterpolationConstraints] = field(default_factory=lambda: [None] * len(CoordinateType), init=False) + + + def set_constraints( + self, + constraints: InterpolationConstraints, + constraint_type: CoordinateType + ): + """ + Set the interpolation constraints for a given constraint type. + + Parameters + ---------- + constraints : InterpolationConstraints + The interpolation constraints. + constraint_type : ConstraintType + The type of constraint. + """ + self.constraints[constraint_type] = constraints + + + def axial_normals(self): + """ + Get the axial normals from the data. + + Returns + ------- + pandas.DataFrame + The axial normals. + """ + + return self.data[self.data['feature_name'] == 'sn' and self.data['coord'] == CoordinateType.AXIAL_FOLIATION_FIELD] + + + def y_normals(self): + """ + Get the y normals from the data. + + Returns + ------- + pandas.DataFrame + The y normals. + """ + + return self.data[self.data['feature_name'] == 'sn' and self.data['coord'] == CoordinateType.FOLD_AXIS_FIELD] + + + def set_axial_surface_field_constraints(self): + """ + Set the axial surface field constraints. + """ + try: + value_constraints = self.axial_normals[['X', 'Y', 'Z', 'value']].to_numpy() + except: + mean_x, mean_y, mean_z = self.axial_normals[['X', 'Y', 'Z']].mean() + value_constraints = numpy.array([mean_x, mean_y, mean_z, 0.0]) + normal_constraints = self.axial_normals[['X', 'Y', 'Z', 'gx', 'gy', 'gz']].to_numpy() + + ic = InterpolationConstraints( + value=value_constraints, + normal_constraints=normal_constraints + ) + + self.set_constraints(ic, CoordinateType.AXIAL_SURFACE_FIELD) + + + def set_fold_axis_field_constraints(self): + """ + Set the fold axis field constraints. + """ + try: + value = self.y_normals[['X', 'Y', 'Z', 'value']].to_numpy() + except: + mean_x, mean_y, mean_z = self.axial_normals[['X', 'Y', 'Z']].mean() + value = numpy.array([mean_x, mean_y, mean_z, 0.0]) + + normal_constraints = self.y_normals[['X', 'Y', 'Z', 'gx', 'gy', 'gz']].to_numpy() + + ic = InterpolationConstraints( + value=value, + normal_constraints=normal_constraints + ) + + self.set_constraints(ic, CoordinateType.FOLD_AXIS_FIELD) + + + + def _getitem__( + self, + constraint_type: CoordinateType + ): + + """ + Get the interpolation constraints for a given constraint type. + + Parameters + ---------- + constraint_type : ConstraintType + The type of constraint. + + Returns + ------- + InterpolationConstraints + The interpolation constraints. + """ + if self.constraints[constraint_type] is None: + + if constraint_type is CoordinateType.AXIAL_SURFACE_FIELD: + + self.set_axial_surface_field_constraints() + + return self.constraints[constraint_type] + + if constraint_type is CoordinateType.FOLD_AXIS_FIELD: + + self.set_fold_axis_field_constraints() + + return self.constraints[constraint_type] + + if self.constraints[constraint_type] is not None: + + return self.constraints[constraint_type] + \ No newline at end of file