diff --git a/applications/OptimizationApplication/python_scripts/algorithms/NLOPT_algorithms.py b/applications/OptimizationApplication/python_scripts/algorithms/NLOPT_algorithms.py index 18f21c26ed2b..277199c43fb0 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/NLOPT_algorithms.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/NLOPT_algorithms.py @@ -59,6 +59,7 @@ def __init__(self, model:Kratos.Model, parameters: Kratos.Parameters, optimizati # controls self.master_control = MasterControl() + self._optimization_problem.AddComponent(self.master_control) for control_name in parameters["controls"].GetStringArray(): control = optimization_problem.GetControl(control_name) self.master_control.AddControl(control) @@ -66,9 +67,12 @@ def __init__(self, model:Kratos.Model, parameters: Kratos.Parameters, optimizati # objective & constraints self.__objective = StandardizedNLOPTObjective(parameters["objective"], self.master_control, self._optimization_problem) + self._optimization_problem.AddComponent(self.__objective) self.__constraints = [] for constraint_settings in parameters["constraints"]: - self.__constraints.append(StandardizedNLOPTConstraint(constraint_settings, self.master_control, self._optimization_problem)) + constraint = StandardizedNLOPTConstraint(constraint_settings, self.master_control, self._optimization_problem) + self._optimization_problem.AddComponent(constraint) + self.__constraints.append(constraint) # nlopt settings NLOPT_settings = parameters["NLOPT_settings"] diff --git a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_gradient_projection.py b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_gradient_projection.py index 94709c5161b6..cc72ba7e9a22 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_gradient_projection.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_gradient_projection.py @@ -14,6 +14,7 @@ from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import OptimizationAlgorithmTimeLogger from KratosMultiphysics.OptimizationApplication.utilities.list_collective_expression_utilities import CollectiveListCollectiveProduct from KratosMultiphysics.OptimizationApplication.utilities.list_collective_expression_utilities import CollectiveListVectorProduct +from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import OutputGradientFields def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem): return AlgorithmGradientProjection(model, parameters, optimization_problem) @@ -48,6 +49,7 @@ def __init__(self, model:Kratos.Model, parameters: Kratos.Parameters, optimizati parameters.ValidateAndAssignDefaults(self.GetDefaultParameters()) self.master_control = MasterControl() # Need to fill it with controls + self._optimization_problem.AddComponent(self.master_control) for control_name in parameters["controls"].GetStringArray(): control = optimization_problem.GetControl(control_name) @@ -65,9 +67,11 @@ def __init__(self, model:Kratos.Model, parameters: Kratos.Parameters, optimizati self.__line_search_method = CreateLineSearch(settings["line_search"], self._optimization_problem) self.__objective = StandardizedObjective(parameters["objective"], self.master_control, self._optimization_problem) + self._optimization_problem.AddComponent(self.__objective) self.__constraints_list: 'list[StandardizedConstraint]' = [] for constraint_param in parameters["constraints"].values(): constraint = StandardizedConstraint(constraint_param, self.master_control, self._optimization_problem) + self._optimization_problem.AddComponent(constraint) self.__constraints_list.append(constraint) self.__control_field = None self.__obj_val = None @@ -163,9 +167,9 @@ def GetCurrentControlField(self): @time_decorator() def Output(self) -> KratosOA.CollectiveExpression: self.algorithm_data.GetBufferedData()["control_field"] = self.__control_field.Clone() - self.__objective.OutputGradientFields(self._optimization_problem, True) + OutputGradientFields(self.__objective, self._optimization_problem, True) for constraint in self.__constraints_list: - constraint.OutputGradientFields(self._optimization_problem, constraint.GetStandardizedValue() > 0.0) + OutputGradientFields(constraint, self._optimization_problem, True) for process in self._optimization_problem.GetListOfProcesses("output_processes"): if process.IsOutputStep(): process.PrintOutput() diff --git a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_relaxed_gradient_projection.py b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_relaxed_gradient_projection.py index 61297980c970..5d0956bd7c82 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_relaxed_gradient_projection.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_relaxed_gradient_projection.py @@ -14,6 +14,7 @@ from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import OptimizationAlgorithmTimeLogger from KratosMultiphysics.OptimizationApplication.utilities.list_collective_expression_utilities import CollectiveListCollectiveProduct from KratosMultiphysics.OptimizationApplication.utilities.list_collective_expression_utilities import CollectiveListVectorProduct +from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import OutputGradientFields import math @@ -54,6 +55,7 @@ def __init__(self, model:Kratos.Model, parameters: Kratos.Parameters, optimizati parameters.ValidateAndAssignDefaults(self.GetDefaultParameters()) self.master_control = MasterControl() # Need to fill it with controls + self._optimization_problem.AddComponent(self.master_control) for control_name in parameters["controls"].GetStringArray(): control = optimization_problem.GetControl(control_name) @@ -73,9 +75,11 @@ def __init__(self, model:Kratos.Model, parameters: Kratos.Parameters, optimizati self.__line_search_method = CreateLineSearch(settings["line_search"], self._optimization_problem) self.__objective = StandardizedObjective(parameters["objective"], self.master_control, self._optimization_problem) + self._optimization_problem.AddComponent(self.__objective) self.__constraints_list: 'list[StandardizedRGPConstraint]' = [] for constraint_param in parameters["constraints"].values(): constraint = StandardizedRGPConstraint(constraint_param, self.master_control, self._optimization_problem, self.GetMinimumBufferSize()) + self._optimization_problem.AddComponent(constraint) self.__constraints_list.append(constraint) self.__control_field = None self.__obj_val = None @@ -208,9 +212,9 @@ def GetCurrentControlField(self): @time_decorator() def Output(self) -> KratosOA.CollectiveExpression: self.algorithm_data.GetBufferedData()["control_field"] = self.__control_field.Clone() - self.__objective.OutputGradientFields(self._optimization_problem, True) + OutputGradientFields(self.__objective, self._optimization_problem, True) for constraint in self.__constraints_list: - constraint.OutputGradientFields(self._optimization_problem, constraint.GetStandardizedValue() > 0.0) + OutputGradientFields(constraint, self._optimization_problem, True) for process in self._optimization_problem.GetListOfProcesses("output_processes"): if process.IsOutputStep(): process.PrintOutput() diff --git a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_steepest_descent.py b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_steepest_descent.py index 451b1117cee0..156387df0920 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_steepest_descent.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_steepest_descent.py @@ -42,6 +42,7 @@ def __init__(self, model:Kratos.Model, parameters: Kratos.Parameters, optimizati parameters.ValidateAndAssignDefaults(self.GetDefaultParameters()) self.master_control = MasterControl() # Need to fill it with controls + self._optimization_problem.AddComponent(self.master_control) for control_name in parameters["controls"].GetStringArray(): control = optimization_problem.GetControl(control_name) @@ -59,6 +60,7 @@ def __init__(self, model:Kratos.Model, parameters: Kratos.Parameters, optimizati self.__line_search_method = CreateLineSearch(settings["line_search"], self._optimization_problem) self.__objective = StandardizedObjective(parameters["objective"], self.master_control, self._optimization_problem) + self._optimization_problem.AddComponent(self.__objective) self.__control_field = None self.__obj_val = None diff --git a/applications/OptimizationApplication/python_scripts/controls/master_control.py b/applications/OptimizationApplication/python_scripts/controls/master_control.py index 3d2cd2d64521..05eb4f788853 100644 --- a/applications/OptimizationApplication/python_scripts/controls/master_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/master_control.py @@ -192,3 +192,6 @@ def Initialize(self) -> None: def Finalize(self) -> None: CallOnAll(self.__list_of_controls, Control.Finalize) + + def GetName(self) -> str: + return "master_control" diff --git a/applications/OptimizationApplication/python_scripts/execution_policies/execution_policy_decorator.py b/applications/OptimizationApplication/python_scripts/execution_policies/execution_policy_decorator.py index ac36ae826733..45a2e1fd9611 100644 --- a/applications/OptimizationApplication/python_scripts/execution_policies/execution_policy_decorator.py +++ b/applications/OptimizationApplication/python_scripts/execution_policies/execution_policy_decorator.py @@ -3,7 +3,7 @@ from KratosMultiphysics.OptimizationApplication.execution_policies.execution_policy import ExecutionPolicy from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import FileLogger from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import TimeLogger -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import OptimizationComponentFactory +from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import OptimizationComponentFactory from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import CallOnAll diff --git a/applications/OptimizationApplication/python_scripts/optimization_analysis.py b/applications/OptimizationApplication/python_scripts/optimization_analysis.py index 58866478e369..43d703f4c8fc 100644 --- a/applications/OptimizationApplication/python_scripts/optimization_analysis.py +++ b/applications/OptimizationApplication/python_scripts/optimization_analysis.py @@ -4,8 +4,7 @@ from KratosMultiphysics.OptimizationApplication.model_part_controllers.model_part_controller import ModelPartController from KratosMultiphysics.OptimizationApplication.execution_policies.execution_policy_decorator import ExecutionPolicyDecorator from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction -from KratosMultiphysics.OptimizationApplication.controls.control import Control -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import OptimizationComponentFactory +from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import OptimizationComponentFactory from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import CallOnAll from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import OptimizationAnalysisTimeLogger diff --git a/applications/OptimizationApplication/python_scripts/processes/optimization_problem_ascii_output_process.py b/applications/OptimizationApplication/python_scripts/processes/optimization_problem_ascii_output_process.py index 46ede75da3f3..b354639e7332 100644 --- a/applications/OptimizationApplication/python_scripts/processes/optimization_problem_ascii_output_process.py +++ b/applications/OptimizationApplication/python_scripts/processes/optimization_problem_ascii_output_process.py @@ -7,9 +7,8 @@ from KratosMultiphysics.OptimizationApplication.execution_policies.execution_policy import ExecutionPolicy from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem -from KratosMultiphysics.OptimizationApplication.utilities.buffered_dict import BufferedDict -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import GetAllComponentFullNamesWithData -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import GetComponentHavingDataByFullName +from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetAllComponentFullNamesWithData +from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentHavingDataByFullName def Factory(_: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ExecutionPolicy: if not parameters.Has("settings"): @@ -96,23 +95,23 @@ def __init__(self, parameters: Kratos.Parameters, optimization_problem: Optimiza raise RuntimeError("The \"bool_values\" should have only two strings corresponding to False and True values in the mentioned order.") self.list_of_components: 'list[Union[str, ResponseFunction, Control, ExecutionPolicy]]' = [] + list_of_component_names = parameters["list_of_output_components"].GetStringArray() + if len(list_of_component_names) == 1 and list_of_component_names[0] == "all": + list_of_component_names = GetAllComponentFullNamesWithData(optimization_problem) + + for component_name in list_of_component_names: + self.list_of_components.append(GetComponentHavingDataByFullName(component_name, optimization_problem)) + self.list_of_headers: 'list[tuple[Any, dict[str, Header]]]' = [] self.initialized_headers = False - self.list_of_component_names = parameters["list_of_output_components"].GetStringArray() def IsOutputStep(self) -> bool: return True def PrintOutput(self) -> None: if not self.initialized_headers: - if len(self.list_of_component_names) == 1 and self.list_of_component_names[0] == "all": - self.list_of_component_names = GetAllComponentFullNamesWithData(self.optimization_problem) - - for component_name in self.list_of_component_names: - self.list_of_components.append(GetComponentHavingDataByFullName(component_name, self.optimization_problem)) - # now get the buffered data headers - self.list_of_headers = self._GetHeaders(lambda x: x.GetBufferedData() if x.HasDataBuffer() else BufferedDict()) + self.list_of_headers = self._GetHeaders(lambda x: x.GetBufferedData()) # write the ehader information self._WriteHeaders() self.initialized_headers = True @@ -169,12 +168,10 @@ def _WriteHeaders(self): componend_data_view = ComponentDataView(component, self.optimization_problem) buffered_dict = componend_data_view.GetUnBufferedData() component_name = componend_data_view.GetComponentName() - # check if there are values to be written under the component name, if not skip the component. - if len(header_info_dict): - msg_header = f"{msg_header}# \t" + component_name + ":\n" - for k, header in header_info_dict.items(): - component_name_header = header.GetHeaderName().strip()[len(component_name)+1:] - msg_header = f"{msg_header}# \t\t" + component_name_header + ": " + header.GetValueStr(buffered_dict[k]).strip() + "\n" + msg_header = f"{msg_header}# \t" + component_name + ":\n" + for k, header in header_info_dict.items(): + component_name_header = header.GetHeaderName().strip()[len(component_name)+1:] + msg_header = f"{msg_header}# \t\t" + component_name_header + ": " + header.GetValueStr(buffered_dict[k]).strip() + "\n" msg_header = f"{msg_header}# ------------ End of initial values ------------\n" msg_header = f"{msg_header}# -----------------------------------------------\n" @@ -207,6 +204,5 @@ def _GetHeaders(self, dict_getter_method) -> 'list[tuple[Any, dict[str, Header] if header_name in [header.GetHeaderName().strip() for header in header_info_dict.values()]: Kratos.Logger.PrintWarning(self.__class__.__name__, "Second value with same header name = \"" + header_name + "\" found.") header_info_dict[k] = Header(header_name, v, self.format_info) - if len(header_info_dict): - list_of_headers.append([component, header_info_dict]) + list_of_headers.append([component, header_info_dict]) return list_of_headers \ No newline at end of file diff --git a/applications/OptimizationApplication/python_scripts/processes/optimization_problem_graph_output_process.py b/applications/OptimizationApplication/python_scripts/processes/optimization_problem_graph_output_process.py index 82785dac65ec..935f446d38d4 100644 --- a/applications/OptimizationApplication/python_scripts/processes/optimization_problem_graph_output_process.py +++ b/applications/OptimizationApplication/python_scripts/processes/optimization_problem_graph_output_process.py @@ -6,7 +6,7 @@ import KratosMultiphysics as Kratos from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import GetComponentHavingDataByFullName +from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentHavingDataByFullName def Factory(_: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> Kratos.OutputProcess: if not parameters.Has("settings"): diff --git a/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py b/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py index 76cf5e914c04..60c89154b3c7 100644 --- a/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py +++ b/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py @@ -10,8 +10,8 @@ from KratosMultiphysics.OptimizationApplication.execution_policies.execution_policy import ExecutionPolicy from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import GetAllComponentFullNamesWithData -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import GetComponentHavingDataByFullName +from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetAllComponentFullNamesWithData +from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentHavingDataByFullName from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes def Factory(_: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> Any: diff --git a/applications/OptimizationApplication/python_scripts/responses/response_routine.py b/applications/OptimizationApplication/python_scripts/responses/response_routine.py index 4d7a6ccb9b6c..a2c9c9e7d72a 100644 --- a/applications/OptimizationApplication/python_scripts/responses/response_routine.py +++ b/applications/OptimizationApplication/python_scripts/responses/response_routine.py @@ -4,8 +4,6 @@ from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem -from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView class ResponseRoutine: """A class which adds optimization-specific utilities to simplify routines @@ -128,6 +126,9 @@ def CalculateGradient(self) -> KratosOA.CollectiveExpression: # calculate and return the control space gradients from respective controls self.__mapped_gradients = self.__master_control.MapGradient(self.__required_physical_gradients) return self.__mapped_gradients + + def GetMappedGradients(self): + return self.__mapped_gradients def GetRequiredPhysicalGradients(self) -> 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]': """Returns required physical gradients by this response @@ -139,29 +140,8 @@ def GetRequiredPhysicalGradients(self) -> 'dict[SupportedSensitivityFieldVariabl dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]: Required physical gradients. """ return self.__required_physical_gradients + + def GetName(self): + return self.GetReponse().GetName() - def OutputGradientFields(self, optimization_problem: OptimizationProblem, is_gradients_computed: bool) -> None: - unbuffered_data = ComponentDataView(self.GetReponse(), optimization_problem).GetUnBufferedData() - if is_gradients_computed: - # save the physical gradients for post processing in unbuffered data container. - for physical_var, physical_gradient in self.GetRequiredPhysicalGradients().items(): - variable_name = f"d{self.GetResponseName()}_d{physical_var.Name()}" - for physical_gradient_expression in physical_gradient.GetContainerExpressions(): - unbuffered_data.SetValue(variable_name, physical_gradient_expression.Clone(), overwrite=True) - - # save the filtered gradients for post processing in unbuffered data container. - for gradient_container_expression, control in zip(self.__mapped_gradients.GetContainerExpressions(), self.GetMasterControl().GetListOfControls()): - variable_name = f"d{self.GetResponseName()}_d{control.GetName()}" - unbuffered_data.SetValue(variable_name, gradient_container_expression.Clone(), overwrite=True) - else: - # save the physical gradients for post processing in unbuffered data container. - for physical_var, physical_gradient in self.GetRequiredPhysicalGradients().items(): - variable_name = f"d{self.GetResponseName()}_d{physical_var.Name()}" - for physical_gradient_expression in physical_gradient.GetContainerExpressions(): - unbuffered_data.SetValue(variable_name, physical_gradient_expression.Clone() * 0.0, overwrite=True) - - # save the filtered gradients for post processing in unbuffered data container. - for control in self.GetMasterControl().GetListOfControls(): - variable_name = f"d{self.GetResponseName()}_d{control.GetName()}" - unbuffered_data.SetValue(variable_name, control.GetEmptyField(), overwrite=True) diff --git a/applications/OptimizationApplication/python_scripts/utilities/helper_utilities.py b/applications/OptimizationApplication/python_scripts/utilities/helper_utilities.py index 756e9875dd96..e2ea9473227a 100644 --- a/applications/OptimizationApplication/python_scripts/utilities/helper_utilities.py +++ b/applications/OptimizationApplication/python_scripts/utilities/helper_utilities.py @@ -1,9 +1,7 @@ from pathlib import Path -from importlib import import_module from typing import Any import KratosMultiphysics as Kratos -from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.kratos_utilities import GetListOfAvailableApplications from KratosMultiphysics.kratos_utilities import GetKratosMultiphysicsPath from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes @@ -53,60 +51,3 @@ def IsSameContainerExpression(container_expression_1: ContainerExpressionTypes, def HasContainerExpression(container_expression: ContainerExpressionTypes, list_of_container_expressions: 'list[ContainerExpressionTypes]') -> bool: return any([IsSameContainerExpression(container_expression, list_container_expression) for list_container_expression in list_of_container_expressions]) - -def OptimizationComponentFactory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem): - if not parameters.Has("type"): - raise RuntimeError(f"Components created from OptimizationComponentFactory require the \"type\" [ provided paramters = {parameters}].") - - python_type = parameters["type"].GetString() - - if not parameters.Has("module") or parameters["module"].GetString() == "": - # in the case python type comes without a module - # as in the case python_type is in the sys path or the current working directory. - full_module_name = python_type - else: - # in the case python type comes witha a module. - module = parameters["module"].GetString() - full_module_name = f"{module}.{python_type}" - - module = import_module(full_module_name) - if not hasattr(module, "Factory"): - raise RuntimeError(f"Python module {full_module_name} does not have a Factory method.") - - return getattr(module, "Factory")(model, parameters, optimization_problem) - -def GetAllComponentFullNamesWithData(optimization_problem: OptimizationProblem) -> 'list[str]': - data_container = optimization_problem.GetProblemDataContainer() - - list_of_components_full_names_with_data: 'list[str]' = [] - for component_type_str, components_dict in data_container.GetSubItems().items(): - if component_type_str != "object": - component_type_str = Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(component_type_str) + "." - else: - component_type_str = "" - for component_name in components_dict.GetSubItems().keys(): - list_of_components_full_names_with_data.append(f"{component_type_str}{component_name}") - - return list_of_components_full_names_with_data - -def GetComponentHavingDataByFullName(component_full_name: str, optimization_problem: OptimizationProblem) -> Any: - for component_type in optimization_problem.GetComponentContainer().keys(): - snake_case_name = Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(component_type.__name__) - if component_full_name.startswith(snake_case_name): - return optimization_problem.GetComponent(component_full_name[len(snake_case_name) + 1:], component_type) - - data_container = optimization_problem.GetProblemDataContainer() - if data_container.HasValue("object") and data_container["object"].HasValue(component_full_name): - return component_full_name - - msg = "" - for component_type, dict_of_components in optimization_problem.GetComponentContainer().items(): - for sub_item_name in dict_of_components.keys(): - msg += "\n\t" + Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(component_type.__name__) + f".{sub_item_name}" - if data_container.HasValue("object"): - for sub_item_name in data_container["object"].GetSubItems().keys(): - msg += "\n\t" + sub_item_name - - raise RuntimeError(f"\"{component_full_name}\" full component name is not found in the optimization problem. Followings are supported component with full names:" + msg) - - diff --git a/applications/OptimizationApplication/python_scripts/utilities/optimization_problem.py b/applications/OptimizationApplication/python_scripts/utilities/optimization_problem.py index d74bd6a15c90..4ccefe537fe9 100644 --- a/applications/OptimizationApplication/python_scripts/utilities/optimization_problem.py +++ b/applications/OptimizationApplication/python_scripts/utilities/optimization_problem.py @@ -4,8 +4,10 @@ import KratosMultiphysics as Kratos from KratosMultiphysics.OptimizationApplication.utilities.buffered_dict import BufferedDict from KratosMultiphysics.OptimizationApplication.execution_policies.execution_policy import ExecutionPolicy +from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.controls.control import Control +from KratosMultiphysics.OptimizationApplication.responses.response_routine import ResponseRoutine class OptimizationProblem: """This is the main data holder for optimization problems @@ -28,7 +30,9 @@ def __init__(self, echo_level: int = 0) -> None: self.__components: 'dict[Any, dict[str, Any]]' = { ResponseFunction: {}, ExecutionPolicy: {}, - Control: {} + Control: {}, + MasterControl:{}, + ResponseRoutine:{} } # now set the processes dict with different categories of processes @@ -41,14 +45,14 @@ def __init__(self, echo_level: int = 0) -> None: # initialize the step self.__problem_data["step"] = 0 - def GetComponentType(self, component: Union[ExecutionPolicy, ResponseFunction, Control]) -> Any: + def GetComponentType(self, component: Union[ExecutionPolicy, ResponseFunction, Control, MasterControl, ResponseRoutine]) -> Any: for k in self.__components.keys(): if isinstance(component, k): return k return None - def GetComponentName(self, component: Union[ExecutionPolicy, ResponseFunction, Control]) -> str: + def GetComponentName(self, component: Union[ExecutionPolicy, ResponseFunction, Control, MasterControl, ResponseRoutine]) -> str: component_type = self.GetComponentType(component) if not component_type is None: components = self.__components[component_type] @@ -61,7 +65,7 @@ def GetComponentName(self, component: Union[ExecutionPolicy, ResponseFunction, C raise RuntimeError(f"The given {component} not found in components of type {component_type}.") - def AddComponent(self, component: Union[ExecutionPolicy, ResponseFunction, Control]) -> None: + def AddComponent(self, component: Union[ExecutionPolicy, ResponseFunction, Control, MasterControl, ResponseRoutine]) -> None: for k, v in self.__components.items(): if isinstance(component, k): added_component_type = k.__name__ @@ -128,6 +132,40 @@ def RemoveControl(self, name: str) -> None: def AddProcessType(self, process_type: str) -> None: self.__proceses[process_type] = [] + def GetResponseRoutine(self, name: str) -> ResponseRoutine: + return self.GetComponent(name, ResponseRoutine) + + def GetListOfResponseRoutines(self) -> 'list[ResponseRoutine]': + return self.__components[ResponseRoutine].values() + + def HasResponseRoutine(self, name_or_response_routine: 'Union[str, ResponseRoutine]') -> bool: + if isinstance(name_or_response_routine, str): + return name_or_response_routine in [response_routine.GetName() for response_routine in self.GetListOfResponseRoutines()] + elif isinstance(name_or_response_routine, ResponseRoutine): + return name_or_response_routine in self.GetListOfResponseRoutines() + else: + raise RuntimeError(f"Unsupported type provided for name_or_control. Only allowed to have string or Control types.") + + def RemoveResponseRoutine(self, name: str) -> None: + self.RemoveComponent(name, ResponseRoutine) + + def GetMasterControl(self, name: str) -> MasterControl: + return self.GetComponent(name, MasterControl) + + def GetListOfMasterControls(self) -> 'list[MasterControl]': + return self.__components[MasterControl].values() + + def HasMasterControl(self, name_or_master_control: 'Union[str, MasterControl]') -> bool: + if isinstance(name_or_master_control, str): + return name_or_master_control in [master_control.GetName() for master_control in self.GetListOfMasterControls()] + elif isinstance(name_or_master_control, MasterControl): + return name_or_master_control in self.GetListOfMasterControls() + else: + raise RuntimeError(f"Unsupported type provided for name_or_control. Only allowed to have string or Control types.") + + def RemoveMasterControl(self, name: str) -> None: + self.RemoveComponent(name, MasterControl) + def AddProcess(self, process_type: str, process: Kratos.Process) -> None: if process_type not in self.__proceses.keys(): self.__proceses[process_type]: 'list[Kratos.Process]' = [] diff --git a/applications/OptimizationApplication/python_scripts/utilities/optimization_problem_utilities.py b/applications/OptimizationApplication/python_scripts/utilities/optimization_problem_utilities.py new file mode 100644 index 000000000000..37bd462af42f --- /dev/null +++ b/applications/OptimizationApplication/python_scripts/utilities/optimization_problem_utilities.py @@ -0,0 +1,94 @@ +from pathlib import Path +from importlib import import_module +from typing import Any + +import KratosMultiphysics as Kratos +from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem +from KratosMultiphysics.OptimizationApplication.responses.response_routine import ResponseRoutine +from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView + +def OptimizationComponentFactory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem): + if not parameters.Has("type"): + raise RuntimeError(f"Components created from OptimizationComponentFactory require the \"type\" [ provided paramters = {parameters}].") + + python_type = parameters["type"].GetString() + + if not parameters.Has("module") or parameters["module"].GetString() == "": + # in the case python type comes without a module + # as in the case python_type is in the sys path or the current working directory. + full_module_name = python_type + else: + # in the case python type comes witha a module. + module = parameters["module"].GetString() + full_module_name = f"{module}.{python_type}" + + module = import_module(full_module_name) + if not hasattr(module, "Factory"): + raise RuntimeError(f"Python module {full_module_name} does not have a Factory method.") + + return getattr(module, "Factory")(model, parameters, optimization_problem) + +def GetAllComponentFullNamesWithData(optimization_problem: OptimizationProblem) -> 'list[str]': + data_container = optimization_problem.GetProblemDataContainer() + + list_of_components_full_names_with_data: 'list[str]' = [] + for component_type_str, components_dict in data_container.GetSubItems().items(): + if component_type_str != "object": + component_type_str = Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(component_type_str) + "." + else: + component_type_str = "" + for component_name in components_dict.GetSubItems().keys(): + list_of_components_full_names_with_data.append(f"{component_type_str}{component_name}") + + return list_of_components_full_names_with_data + +def GetComponentHavingDataByFullName(component_full_name: str, optimization_problem: OptimizationProblem) -> Any: + data_container = optimization_problem.GetProblemDataContainer() + + name_data = component_full_name.split(".") + + if len(name_data) == 1: + if data_container.HasValue("object") and data_container["object"].HasValue(component_full_name): + return component_full_name + else: + component_type_str = Kratos.StringUtilities.ConvertSnakeCaseToCamelCase(name_data[0]) + component_name = name_data[1] + + for component_type in optimization_problem.GetComponentContainer().keys(): + if component_type.__name__ == component_type_str: + return optimization_problem.GetComponent(component_name, component_type) + + msg = "" + for component_type, dict_of_components in optimization_problem.GetComponentContainer().items(): + for sub_item_name in dict_of_components.keys(): + msg += "\n\t" + Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(component_type.__name__) + f".{sub_item_name}" + if data_container.HasValue("object"): + for sub_item_name in data_container["object"].GetSubItems().keys(): + msg += "\n\t" + sub_item_name + + raise RuntimeError(f"\"{component_full_name}\" full component name is not found in the optimization problem. Followings are supported component with full names:" + msg) + +def OutputGradientFields(response: ResponseRoutine, optimization_problem: OptimizationProblem, is_gradients_computed: bool) -> None: + unbuffered_data = ComponentDataView(response.GetReponse(), optimization_problem).GetUnBufferedData() + if is_gradients_computed: + # save the physical gradients for post processing in unbuffered data container. + for physical_var, physical_gradient in response.GetRequiredPhysicalGradients().items(): + variable_name = f"d{response.GetResponseName()}_d{physical_var.Name()}" + for physical_gradient_expression in physical_gradient.GetContainerExpressions(): + unbuffered_data.SetValue(variable_name, physical_gradient_expression.Clone(), overwrite=True) + + # save the filtered gradients for post processing in unbuffered data container. + for gradient_container_expression, control in zip(response.GetMappedGradients().GetContainerExpressions(), response.GetMasterControl().GetListOfControls()): + variable_name = f"d{response.GetResponseName()}_d{control.GetName()}" + unbuffered_data.SetValue(variable_name, gradient_container_expression.Clone(), overwrite=True) + else: + # save the physical gradients for post processing in unbuffered data container. + for physical_var, physical_gradient in response.GetRequiredPhysicalGradients().items(): + variable_name = f"d{response.GetResponseName()}_d{physical_var.Name()}" + for physical_gradient_expression in physical_gradient.GetContainerExpressions(): + unbuffered_data.SetValue(variable_name, physical_gradient_expression.Clone() * 0.0, overwrite=True) + + # save the filtered gradients for post processing in unbuffered data container. + for control in response.GetMasterControl().GetListOfControls(): + variable_name = f"d{response.GetResponseName()}_d{control.GetName()}" + unbuffered_data.SetValue(variable_name, control.GetEmptyField(), overwrite=True) diff --git a/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_nesterov_accelerated_gradient/summary_orig.csv b/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_nesterov_accelerated_gradient/summary_orig.csv index c4caaeb9297a..c3fd2c0eb2b5 100644 --- a/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_nesterov_accelerated_gradient/summary_orig.csv +++ b/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_nesterov_accelerated_gradient/summary_orig.csv @@ -3,6 +3,7 @@ # Timestamp : not_specified # ----------------------------------------------- # --------------- Initial values ---------------- +# algorithm: # strain_energy: # initial_value: 2.045937642e-02 # ------------ End of initial values ------------ diff --git a/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_steepest_descent/summary_orig.csv b/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_steepest_descent/summary_orig.csv index 1defae9d1af0..4b22168e1941 100644 --- a/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_steepest_descent/summary_orig.csv +++ b/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_steepest_descent/summary_orig.csv @@ -3,6 +3,7 @@ # Timestamp : not_specified # ----------------------------------------------- # --------------- Initial values ---------------- +# algorithm: # strain_energy: # initial_value: 2.045937642e-02 # ------------ End of initial values ------------ diff --git a/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_steepest_descent_qnbb/summary_orig.csv b/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_steepest_descent_qnbb/summary_orig.csv index 22893d0ebc99..4105f7ddcc90 100644 --- a/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_steepest_descent_qnbb/summary_orig.csv +++ b/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_steepest_descent_qnbb/summary_orig.csv @@ -3,6 +3,7 @@ # Timestamp : not_specified # ----------------------------------------------- # --------------- Initial values ---------------- +# algorithm: # strain_energy: # initial_value: 2.045937642e-02 # ------------ End of initial values ------------