KratosOptimizationApplication 10.4.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. KratosMultiphysics/.libs/KratosOptimizationApplication.so +0 -0
  2. KratosMultiphysics/.libs/libKratosOptimizationCore.dylib +0 -0
  3. KratosMultiphysics/OptimizationApplication/__init__.py +19 -0
  4. KratosMultiphysics/OptimizationApplication/algorithms/NLOPT_algorithms.py +255 -0
  5. KratosMultiphysics/OptimizationApplication/algorithms/SciPy_algorithms.py +154 -0
  6. KratosMultiphysics/OptimizationApplication/algorithms/__init__.py +0 -0
  7. KratosMultiphysics/OptimizationApplication/algorithms/algorithm.py +78 -0
  8. KratosMultiphysics/OptimizationApplication/algorithms/algorithm_adam.py +68 -0
  9. KratosMultiphysics/OptimizationApplication/algorithms/algorithm_base.py +393 -0
  10. KratosMultiphysics/OptimizationApplication/algorithms/algorithm_gradient_projection.py +355 -0
  11. KratosMultiphysics/OptimizationApplication/algorithms/algorithm_momentum_relaxed_gradient_projection.py +70 -0
  12. KratosMultiphysics/OptimizationApplication/algorithms/algorithm_nesterov_accelarated_gradient.py +60 -0
  13. KratosMultiphysics/OptimizationApplication/algorithms/algorithm_relaxed_gradient_projection.py +263 -0
  14. KratosMultiphysics/OptimizationApplication/algorithms/algorithm_steepest_descent.py +205 -0
  15. KratosMultiphysics/OptimizationApplication/algorithms/standardized_NLOPT_constraint.py +194 -0
  16. KratosMultiphysics/OptimizationApplication/algorithms/standardized_NLOPT_objective.py +191 -0
  17. KratosMultiphysics/OptimizationApplication/algorithms/standardized_SciPy_constraint.py +123 -0
  18. KratosMultiphysics/OptimizationApplication/algorithms/standardized_SciPy_objective.py +148 -0
  19. KratosMultiphysics/OptimizationApplication/algorithms/standardized_constraint.py +180 -0
  20. KratosMultiphysics/OptimizationApplication/algorithms/standardized_objective.py +133 -0
  21. KratosMultiphysics/OptimizationApplication/algorithms/standardized_rgp_constraint.py +268 -0
  22. KratosMultiphysics/OptimizationApplication/analyses_controller.py +75 -0
  23. KratosMultiphysics/OptimizationApplication/controls/control.py +123 -0
  24. KratosMultiphysics/OptimizationApplication/controls/external_response_function_control.py +149 -0
  25. KratosMultiphysics/OptimizationApplication/controls/master_control.py +198 -0
  26. KratosMultiphysics/OptimizationApplication/controls/material/material_properties_control.py +115 -0
  27. KratosMultiphysics/OptimizationApplication/controls/material/simp_control.py +229 -0
  28. KratosMultiphysics/OptimizationApplication/controls/shape/vertex_morphing_shape_control.py +289 -0
  29. KratosMultiphysics/OptimizationApplication/controls/thickness/shell_thickness_control.py +180 -0
  30. KratosMultiphysics/OptimizationApplication/controls_controller.py +205 -0
  31. KratosMultiphysics/OptimizationApplication/convergence_criteria/avg_abs_improvement_conv_criterion.py +98 -0
  32. KratosMultiphysics/OptimizationApplication/convergence_criteria/combined_conv_criterion.py +87 -0
  33. KratosMultiphysics/OptimizationApplication/convergence_criteria/constraint_conv_criterion.py +68 -0
  34. KratosMultiphysics/OptimizationApplication/convergence_criteria/convergence_criterion.py +26 -0
  35. KratosMultiphysics/OptimizationApplication/convergence_criteria/l2_conv_criterion.py +77 -0
  36. KratosMultiphysics/OptimizationApplication/convergence_criteria/magnitude_reduction_conv_criterion.py +85 -0
  37. KratosMultiphysics/OptimizationApplication/convergence_criteria/max_iter_conv_criterion.py +48 -0
  38. KratosMultiphysics/OptimizationApplication/convergence_criteria/patience_conv_criterion.py +116 -0
  39. KratosMultiphysics/OptimizationApplication/convergence_criteria/target_value_conv_criterion.py +64 -0
  40. KratosMultiphysics/OptimizationApplication/execution_policies/execution_policy.py +46 -0
  41. KratosMultiphysics/OptimizationApplication/execution_policies/execution_policy_decorator.py +67 -0
  42. KratosMultiphysics/OptimizationApplication/execution_policies/independent_analysis_execution_policy.py +78 -0
  43. KratosMultiphysics/OptimizationApplication/execution_policies/kratos_analysis_execution_policy.py +137 -0
  44. KratosMultiphysics/OptimizationApplication/execution_policies/stepping_analysis_execution_policy.py +88 -0
  45. KratosMultiphysics/OptimizationApplication/filtering/explicit_filter.py +124 -0
  46. KratosMultiphysics/OptimizationApplication/filtering/filter.py +188 -0
  47. KratosMultiphysics/OptimizationApplication/filtering/filter_utils.py +55 -0
  48. KratosMultiphysics/OptimizationApplication/filtering/helmholtz_analysis.py +139 -0
  49. KratosMultiphysics/OptimizationApplication/filtering/helmholtz_scalar_solver.py +39 -0
  50. KratosMultiphysics/OptimizationApplication/filtering/helmholtz_shape_solver.py +67 -0
  51. KratosMultiphysics/OptimizationApplication/filtering/helmholtz_solver_base.py +275 -0
  52. KratosMultiphysics/OptimizationApplication/filtering/helmholtz_vector_solver.py +39 -0
  53. KratosMultiphysics/OptimizationApplication/filtering/implicit_filter.py +192 -0
  54. KratosMultiphysics/OptimizationApplication/filtering/python_solvers_wrapper_implicit_filters.py +56 -0
  55. KratosMultiphysics/OptimizationApplication/model_part_controllers/connectivity_preserving_model_part_controller.py +72 -0
  56. KratosMultiphysics/OptimizationApplication/model_part_controllers/external_response_function_model_part_controller.py +110 -0
  57. KratosMultiphysics/OptimizationApplication/model_part_controllers/mdpa_model_part_controller.py +44 -0
  58. KratosMultiphysics/OptimizationApplication/model_part_controllers/model_part_controller.py +19 -0
  59. KratosMultiphysics/OptimizationApplication/model_parts_controller.py +92 -0
  60. KratosMultiphysics/OptimizationApplication/optimization_analysis.py +146 -0
  61. KratosMultiphysics/OptimizationApplication/optimizations_controller.py +223 -0
  62. KratosMultiphysics/OptimizationApplication/optimizer.py +61 -0
  63. KratosMultiphysics/OptimizationApplication/processes/optimization_problem_ascii_output_process.py +212 -0
  64. KratosMultiphysics/OptimizationApplication/processes/optimization_problem_field_output_process.py +122 -0
  65. KratosMultiphysics/OptimizationApplication/processes/optimization_problem_graph_output_process.py +184 -0
  66. KratosMultiphysics/OptimizationApplication/processes/optimization_problem_hdf5_output_process.py +84 -0
  67. KratosMultiphysics/OptimizationApplication/processes/optimization_problem_vtu_output_process.py +94 -0
  68. KratosMultiphysics/OptimizationApplication/processes/spatial_statistics_computation_process.py +81 -0
  69. KratosMultiphysics/OptimizationApplication/responses/__init__.py +0 -0
  70. KratosMultiphysics/OptimizationApplication/responses/additive_manufacturing_responses.py +410 -0
  71. KratosMultiphysics/OptimizationApplication/responses/analysis_based_response_function_factory.py +14 -0
  72. KratosMultiphysics/OptimizationApplication/responses/analysis_free_response_function_factory.py +14 -0
  73. KratosMultiphysics/OptimizationApplication/responses/base_response.py +66 -0
  74. KratosMultiphysics/OptimizationApplication/responses/binary_operator_response_function.py +103 -0
  75. KratosMultiphysics/OptimizationApplication/responses/combined_response_function.py +127 -0
  76. KratosMultiphysics/OptimizationApplication/responses/discrete_value_residual_response_function.py +131 -0
  77. KratosMultiphysics/OptimizationApplication/responses/evaluation_response_function.py +68 -0
  78. KratosMultiphysics/OptimizationApplication/responses/external_response_function.py +87 -0
  79. KratosMultiphysics/OptimizationApplication/responses/geometric_centroid_deviation_response_function.py +97 -0
  80. KratosMultiphysics/OptimizationApplication/responses/linear_strain_energy_response_function.py +72 -0
  81. KratosMultiphysics/OptimizationApplication/responses/literal_value_response_function.py +33 -0
  82. KratosMultiphysics/OptimizationApplication/responses/log_response_function.py +47 -0
  83. KratosMultiphysics/OptimizationApplication/responses/mass_response_function.py +71 -0
  84. KratosMultiphysics/OptimizationApplication/responses/response_function.py +126 -0
  85. KratosMultiphysics/OptimizationApplication/responses/response_routine.py +158 -0
  86. KratosMultiphysics/OptimizationApplication/responses/structural_responses.py +335 -0
  87. KratosMultiphysics/OptimizationApplication/responses_controller.py +390 -0
  88. KratosMultiphysics/OptimizationApplication/utilities/buffered_dict.py +399 -0
  89. KratosMultiphysics/OptimizationApplication/utilities/component_data_view.py +74 -0
  90. KratosMultiphysics/OptimizationApplication/utilities/helper_utilities.py +40 -0
  91. KratosMultiphysics/OptimizationApplication/utilities/logger_utilities.py +222 -0
  92. KratosMultiphysics/OptimizationApplication/utilities/model_part_utilities.py +117 -0
  93. KratosMultiphysics/OptimizationApplication/utilities/opt_line_search.py +173 -0
  94. KratosMultiphysics/OptimizationApplication/utilities/opt_projection.py +191 -0
  95. KratosMultiphysics/OptimizationApplication/utilities/optimization_problem.py +237 -0
  96. KratosMultiphysics/OptimizationApplication/utilities/optimization_problem_utilities.py +237 -0
  97. KratosMultiphysics/OptimizationApplication/utilities/response_utilities.py +249 -0
  98. KratosMultiphysics/OptimizationApplication/utilities/timer.py +45 -0
  99. KratosMultiphysics/OptimizationApplication/utilities/union_utilities.py +6 -0
  100. kratosoptimizationapplication-10.4.4.dist-info/METADATA +25 -0
  101. kratosoptimizationapplication-10.4.4.dist-info/RECORD +106 -0
  102. kratosoptimizationapplication-10.4.4.dist-info/WHEEL +6 -0
  103. kratosoptimizationapplication.dylibs/libKratosCore.dylib +4 -0
  104. kratosoptimizationapplication.dylibs/libgcc_s.1.1.dylib +0 -0
  105. kratosoptimizationapplication.dylibs/libgomp.1.dylib +0 -0
  106. kratosoptimizationapplication.dylibs/libstdc++.6.dylib +0 -0
@@ -0,0 +1,149 @@
1
+ import numpy
2
+ from typing import Optional
3
+ import KratosMultiphysics as Kratos
4
+ from KratosMultiphysics.OptimizationApplication.controls.control import Control
5
+ from KratosMultiphysics.OptimizationApplication.filtering.filter import Filter
6
+ from KratosMultiphysics.OptimizationApplication.filtering.filter import Factory as FilterFactory
7
+ from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation
8
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
9
+ from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
10
+ from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes
11
+ from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import TimeLogger
12
+
13
+ def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> Control:
14
+ if not parameters.Has("name"):
15
+ raise RuntimeError(f"ExternalResponseFunctionControl instantiation requires a \"name\" in parameters [ parameters = {parameters}].")
16
+ if not parameters.Has("settings"):
17
+ raise RuntimeError(f"ExternalResponseFunctionControl instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
18
+
19
+ return ExternalResponseFunctionControl(parameters["name"].GetString(), model, parameters["settings"], optimization_problem)
20
+
21
+ class ExternalResponseFunctionControl(Control):
22
+ def __init__(self, control_name: str, model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> None:
23
+ super().__init__(control_name)
24
+
25
+ default_parameters = Kratos.Parameters("""{
26
+ "controlled_model_part_names": [],
27
+ "design_variable" : "CUSTOM_DESIGN_VARIABLE",
28
+ "use_filtering" : false,
29
+ "filter_settings" : {},
30
+ "output_all_fields" : false
31
+ }""")
32
+ parameters.ValidateAndAssignDefaults(default_parameters)
33
+
34
+ self.model = model
35
+ self.optimization_problem = optimization_problem
36
+
37
+ self.model_part_operation = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, f"control_{self.GetName()}", parameters["controlled_model_part_names"].GetStringArray(), False)
38
+ self.model_part: 'Optional[Kratos.ModelPart]' = None
39
+
40
+ self.design_variable: SupportedSensitivityFieldVariableTypes = Kratos.KratosGlobals.GetVariable(parameters["design_variable"].GetString())
41
+ self.output_all_fields = parameters["output_all_fields"].GetBool()
42
+
43
+ if parameters["use_filtering"].GetBool():
44
+ self.filter: 'Optional[Filter]' = FilterFactory(self.model, self.model_part_operation.GetModelPartFullName(), self.design_variable, Kratos.Globals.DataLocation.NodeNonHistorical, parameters["filter_settings"])
45
+ else:
46
+ self.filter = None
47
+
48
+
49
+ def Initialize(self) -> None:
50
+ self.model_part = self.model_part_operation.GetModelPart()
51
+
52
+ ComponentDataView(self, self.optimization_problem).SetDataBuffer(1)
53
+
54
+ # initialize the filter
55
+ if self.filter:
56
+ self.filter.SetComponentDataView(ComponentDataView(self, self.optimization_problem))
57
+ self.filter.Initialize()
58
+
59
+ self.physical_phi_field = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, self.design_variable)
60
+ self.physical_phi_field.CollectData()
61
+
62
+ if self.filter:
63
+ # take the physical and control field the same
64
+ self.control_phi_field = self.filter.UnfilterField(self.physical_phi_field)
65
+ else:
66
+ self.control_phi_field = self.physical_phi_field.Clone()
67
+
68
+ # now update the physical thickness field
69
+ self._UpdateAndOutputFields(self.GetEmptyField())
70
+
71
+ def Check(self) -> None:
72
+ if self.filter:
73
+ self.filter.Check()
74
+
75
+ def Finalize(self) -> None:
76
+ if self.filter:
77
+ self.filter.Finalize()
78
+
79
+ def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]':
80
+ return [self.design_variable]
81
+
82
+ def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
83
+ ta = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, self.design_variable)
84
+ ta.data[:] = 0.0
85
+ return ta
86
+
87
+ def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
88
+ return self.control_phi_field.Clone()
89
+
90
+ def MapGradient(self, physical_variable_gradient_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
91
+ with TimeLogger("ExternalResponseFunctionControl::MapGradient", None, "Finished",False):
92
+ keys = physical_variable_gradient_map.keys()
93
+ if len(keys) != 1:
94
+ raise RuntimeError(f"Provided more than required gradient fields for control \"{self.GetName()}\". Following are the variables:\n\t" + "\n\t".join([k.Name() for k in keys]))
95
+ if self.design_variable not in keys:
96
+ raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. {self.design_variable.Name()} not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys]))
97
+
98
+ physical_gradient = physical_variable_gradient_map[self.design_variable]
99
+ if physical_gradient.GetContainer() != self.model_part.Nodes:
100
+ raise RuntimeError(f"Gradients for the required container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {physical_gradient.GetModelPart().FullName()} ]")
101
+
102
+ if self.filter:
103
+ # now filter the field
104
+ filtered_gradient = self.filter.BackwardFilterIntegratedField(physical_gradient)
105
+ else:
106
+ filtered_gradient = physical_gradient.Clone()
107
+
108
+ return filtered_gradient
109
+
110
+ def Update(self, new_control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool:
111
+ if new_control_field.GetContainer() != self.model_part.Nodes:
112
+ raise RuntimeError(f"Updates for the required container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()} ]")
113
+
114
+ update = new_control_field.Clone()
115
+ update.data[:] -= self.control_phi_field.data
116
+ if numpy.linalg.norm(update.data) > 1e-15:
117
+ with TimeLogger(self.__class__.__name__, f"Updating {self.GetName()}...", f"Finished updating of {self.GetName()}.",False):
118
+ # update the control thickness field
119
+ self.control_phi_field.data[:] = new_control_field.data
120
+ # now update the physical field
121
+ self._UpdateAndOutputFields(update)
122
+
123
+ if self.filter:
124
+ self.filter.Update()
125
+ return True
126
+ return False
127
+
128
+ def _UpdateAndOutputFields(self, update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None:
129
+ if self.filter:
130
+ # filter the control field
131
+ filtered_update = self.filter.ForwardFilterField(update)
132
+ else:
133
+ filtered_update = update.Clone()
134
+
135
+ self.physical_phi_field.data[:] += filtered_update.data
136
+ Kratos.TensorAdaptors.VariableTensorAdaptor(self.physical_phi_field, self.design_variable, copy=False).StoreData()
137
+
138
+ # add the values of the control to the optimization problem.
139
+ component_data_view = ComponentDataView(self, self.optimization_problem)
140
+ for i, v in enumerate(self.physical_phi_field.data):
141
+ component_data_view.GetBufferedData().SetValue(f"{self.model_part.FullName()}_point_{i+1}", float(v))
142
+
143
+ # now output the fields
144
+ un_buffered_data = ComponentDataView(self, self.optimization_problem).GetUnBufferedData()
145
+ un_buffered_data.SetValue(f"{self.GetName()}_{self.design_variable.Name()}", self.physical_phi_field.Clone(), overwrite=True)
146
+ if self.output_all_fields:
147
+ un_buffered_data.SetValue(f"{self.GetName()}_{self.design_variable.Name()}_update", update.Clone(), overwrite=True)
148
+ un_buffered_data.SetValue(f"{self.GetName()}_{self.design_variable.Name()}_filtered_update", filtered_update.Clone(), overwrite=True)
149
+ un_buffered_data.SetValue(f"{self.GetName()}_{self.design_variable.Name()}_control_phi", self.control_phi_field.Clone(), overwrite=True)
@@ -0,0 +1,198 @@
1
+ import typing
2
+ import KratosMultiphysics as Kratos
3
+ from KratosMultiphysics.OptimizationApplication.controls.control import Control
4
+ from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes
5
+ from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator
6
+ from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import CallOnAll
7
+
8
+ class MasterControl:
9
+ """Master control class.
10
+
11
+ This class is used to simplify working with many controls at once. Following responsibilities are assumed:
12
+ 1. Maps physical gradients from different domains to one @ref Kratos::CombinedTensorAdaptor (using MapGradient).
13
+ 2. Updates each respective domain from updates given by one @ref Kratos::CombinedTensorAdaptor (using Update).
14
+
15
+ There should be only one master control class per optimization problem.
16
+
17
+ """
18
+ def __init__(self) -> None:
19
+ self.__list_of_controls: 'list[Control]' = []
20
+
21
+ def AddControl(self, control: Control) -> None:
22
+ """Adds a given control to the master control.
23
+
24
+ Args:
25
+ control (Control): Control to be added
26
+ """
27
+ self.__list_of_controls.append(control)
28
+
29
+ def GetListOfControls(self) -> 'list[Control]':
30
+ """Returns the list of controls in the master control.
31
+
32
+ Returns:
33
+ list[Control]: List of controls.
34
+ """
35
+ return self.__list_of_controls
36
+
37
+ def GetPhysicalKratosVariableMap(self) -> 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]':
38
+ """Returns map of physical variables and @ref Kratos::CombinedTensorAdaptor from each control.
39
+
40
+ This returns a map of physical control variables and a @ref Kratos::CombinedTensorAdaptor. The @ref Kratos::CombinedTensorAdaptor will contain
41
+ all the @ref Kratos::TensorAdaptor for respective control's control domains for each physical control variable. The repeated @ref Kratos::TensorAdaptor s
42
+ for the same physical control variable is omitted to avoid double calculations.
43
+
44
+ Returns:
45
+ dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]: Physical control variable and @ref Kratos::CombinedTensorAdaptor map.
46
+ """
47
+
48
+ physical_variable_containers_dict: 'dict[SupportedSensitivityFieldVariableTypes, list[typing.Union[Kratos.NodesArray, Kratos.ElementsArray, Kratos.ConditionsArray]]]' = {}
49
+ for control in self.__list_of_controls:
50
+ for physical_variable in control.GetPhysicalKratosVariables():
51
+ # check whether the physical variable is already there.
52
+ if not physical_variable in physical_variable_containers_dict.keys():
53
+ physical_variable_containers_dict[physical_variable] = []
54
+
55
+ # check whether the container for that physical variable is already there.
56
+ control_ta = control.GetEmptyField()
57
+ if control_ta.GetContainer() not in physical_variable_containers_dict[physical_variable]:
58
+ physical_variable_containers_dict[physical_variable].append(control_ta.GetContainer())
59
+
60
+ physical_variable_combined_ta_dict: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = {}
61
+ for variable, containers_list in physical_variable_containers_dict.items():
62
+ physical_variable_combined_ta_dict[variable] = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.DoubleTensorAdaptor(Kratos.TensorAdaptors.VariableTensorAdaptor(container, variable), copy=False) for container in containers_list], perform_collect_data_recursively=False, perform_store_data_recursively=False)
63
+
64
+ return physical_variable_combined_ta_dict
65
+
66
+ def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor:
67
+ """Returns empty CombinedTensorAdaptor containing empty TensorAdaptor for each control.
68
+
69
+ Returns:
70
+ Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Empty CombinedTensorAdaptor
71
+ """
72
+ ta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([control.GetEmptyField() for control in self.__list_of_controls], perform_collect_data_recursively=False, perform_store_data_recursively=False)
73
+ ta.CollectData() # reading all the data from each ta adaptor to the combined tensor adaptor
74
+ return ta
75
+
76
+ def GetControlField(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor:
77
+ """Returns CombinedTensorAdaptor containing control field TensorAdaptor for each control.
78
+
79
+ Returns:
80
+ Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Control field CombinedTensorAdaptor
81
+ """
82
+ ta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([control.GetControlField() for control in self.__list_of_controls], perform_collect_data_recursively=False, perform_store_data_recursively=False)
83
+ ta.CollectData() # reading all the data from each ta adaptor to the combined tensor adaptor
84
+ return ta
85
+
86
+ @time_decorator()
87
+ def MapGradient(self, physical_space_gradient_variable_and_combined_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor:
88
+ """Maps physical space gradients to a combined tensor adaptor.
89
+
90
+ This method maps sensitivities w.r.t. physical space variables to control space by using each control. It is done by converting input
91
+ map with @ref Kratos::CombinedTensorAdaptor to a map with @ref Kratos::TensorAdaptor. The following is a pseudo example:
92
+
93
+ input:
94
+
95
+ physical_space_gradient_variable_and_combined_tensor_adaptor_map = {
96
+ "YOUND_MODULUS": [ControlDomain1, ControlDomain2],
97
+ "DENSITY" : [ControlDomain1],
98
+ "VISCOSITY" : [ControlDomain2],
99
+ }
100
+
101
+ control info:
102
+ control1: domain = ControlDomain1
103
+ physical_vars = YOUND_MODULUS, DENSITY
104
+
105
+ control2: domain = ControlDomain2
106
+ physical_vars = VISCOSITY, DENSITY
107
+
108
+
109
+ from above information, following two maps are created and passed to each control to obtain one @ref Kratos::TensorAdaptor from each control.
110
+ control_specific_maps:
111
+ for control1: {YOUND_MODULUS: ControlDomain1, DENSITY: ControlDomain1}
112
+ for control2: {VISCOSITY: ControlDomain2, DENSITY: A zero valued ControlDomain}
113
+
114
+ then returned mapped gradients are added to one @ref Kratos::CombinedTensorAdaptor.
115
+
116
+ In here, the missing gradients for required physical variables will be assumed to be zero.
117
+
118
+ This converts given map of sensitivities w.r.t. different physical space variables to one sensitivities in control space and aggregated
119
+ to one @ref Kratos::CombinedTensorAdaptor.
120
+
121
+ Args:
122
+ physical_space_gradient_variable_and_combined_tensor_adaptor_map (dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]): Map of physical space sensitivities.
123
+
124
+ Returns:
125
+ Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Control space sensitivities.
126
+ """
127
+
128
+
129
+ mapped_gradients: 'list[Kratos.TensorAdaptors.DoubleTensorAdaptor]' = []
130
+
131
+ for control in self.__list_of_controls:
132
+ # iterate through each control to create its own container map from the combined tensor adaptor map given as input
133
+ control_physical_sensitivities_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]' = {}
134
+ for physical_control_variable in control.GetPhysicalKratosVariables():
135
+ # first assume the gradients for this physical_control_variable is zero, hence get the zero valued tensor adaptor.
136
+ control_ta = control.GetEmptyField()
137
+
138
+ # get the required physical variables from control.
139
+ if physical_control_variable in physical_space_gradient_variable_and_combined_tensor_adaptor_map.keys():
140
+ # if the sensitivities for the given physical control variable exists, then try to find whether
141
+ # for this specific control the physical control variable sensitivities exists.
142
+
143
+ sensitivity_cta = physical_space_gradient_variable_and_combined_tensor_adaptor_map[physical_control_variable]
144
+ for ta in sensitivity_cta.GetTensorAdaptors():
145
+ if ta.GetContainer() == control_ta.GetContainer():
146
+ # there exists for this control's physical variables sensitivities.
147
+ control_physical_sensitivities_tensor_adaptor_map[physical_control_variable] = ta
148
+ break
149
+
150
+ if physical_control_variable not in control_physical_sensitivities_tensor_adaptor_map.keys():
151
+ # If it is found from input gradients, the tensor_adaptor will have those values,
152
+ # otherwise it will have representative zero tensor_adaptor.
153
+ control_physical_sensitivities_tensor_adaptor_map[physical_control_variable] = control_ta
154
+
155
+ # map the physical control variable sensitivities to one control space
156
+ mapped_gradients.append(control.MapGradient(control_physical_sensitivities_tensor_adaptor_map))
157
+
158
+ result = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([mapped_gradient for mapped_gradient in mapped_gradients], perform_collect_data_recursively=False, perform_store_data_recursively=False)
159
+ result.CollectData()
160
+ return result
161
+
162
+ @time_decorator()
163
+ def Update(self, update_combined_tensor_adaptor: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor) -> 'dict[Control, bool]':
164
+ """Update each control with given combined tensor adaptor's respective tensor adaptor.
165
+
166
+ Args:
167
+ update_combined_tensor_adaptor (Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor): Update
168
+
169
+ Raises:
170
+ RuntimeError: If number of controls and number of tensor adaptors mismatch.
171
+
172
+ Returns:
173
+ dict[Control, bool]: A map with control and a boolean whether the update changed anything in that control.
174
+ """
175
+ if len(self.__list_of_controls) != len(update_combined_tensor_adaptor.GetTensorAdaptors()):
176
+ raise RuntimeError(f"Controls size and update size mismatch [ number of controls: {len(self.__list_of_controls)}, number of tensor adaptors: {len(update_combined_tensor_adaptor.GetTensorAdaptors())} ].")
177
+
178
+ update_map: 'dict[Control, bool]' = {}
179
+ for control, ta in zip(self.__list_of_controls, update_combined_tensor_adaptor.GetTensorAdaptors()):
180
+ update_map[control] = control.Update(ta)
181
+ if update_map[control]:
182
+ Kratos.Logger.PrintInfo(f"Control {control.GetName()} updated.")
183
+ else:
184
+ Kratos.Logger.PrintInfo(f"Control {control.GetName()} not updated")
185
+
186
+ return update_map
187
+
188
+ def Check(self) -> None:
189
+ CallOnAll(self.__list_of_controls, Control.Check)
190
+
191
+ def Initialize(self) -> None:
192
+ CallOnAll(self.__list_of_controls, Control.Initialize)
193
+
194
+ def Finalize(self) -> None:
195
+ CallOnAll(self.__list_of_controls, Control.Finalize)
196
+
197
+ def GetName(self) -> str:
198
+ return "master_control"
@@ -0,0 +1,115 @@
1
+ import numpy
2
+ from typing import Optional
3
+
4
+ import KratosMultiphysics as Kratos
5
+ import KratosMultiphysics.OptimizationApplication as KratosOA
6
+ from KratosMultiphysics.OptimizationApplication.controls.control import Control
7
+ from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes
8
+ from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation
9
+
10
+ def Factory(model: Kratos.Model, parameters: Kratos.Parameters, _) -> Control:
11
+ if not parameters.Has("name"):
12
+ raise RuntimeError(f"MaterialPropertiesControl instantiation requires a \"name\" in parameters [ parameters = {parameters}].")
13
+ if not parameters.Has("settings"):
14
+ raise RuntimeError(f"MaterialPropertiesControl instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
15
+
16
+ return MaterialPropertiesControl(parameters["name"].GetString(), model, parameters["settings"])
17
+
18
+ class MaterialPropertiesControl(Control):
19
+ """Material properties control
20
+
21
+ This is a generic material properties control which creates a control
22
+ for the specified control variable. This does not do any filtering.
23
+
24
+ TODO: Extend with filtering techniques when they are implemented.
25
+
26
+ """
27
+ def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters):
28
+ super().__init__(name)
29
+
30
+ default_settings = Kratos.Parameters("""{
31
+ "model_part_names" : [""],
32
+ "control_variable_name" : "",
33
+ "consider_recursive_property_update": false
34
+ }""")
35
+ parameters.ValidateAndAssignDefaults(default_settings)
36
+
37
+ self.model = model
38
+
39
+ control_variable_name = parameters["control_variable_name"].GetString()
40
+ control_variable_type = Kratos.KratosGlobals.GetVariableType(control_variable_name)
41
+ if control_variable_type != "Double":
42
+ raise RuntimeError(f"{control_variable_name} with {control_variable_type} type is not supported. Only supports double variables")
43
+ self.controlled_physical_variable = Kratos.KratosGlobals.GetVariable(control_variable_name)
44
+
45
+ controlled_model_part_names = parameters["model_part_names"].GetStringArray()
46
+ if len(controlled_model_part_names) == 0:
47
+ raise RuntimeError(f"No model parts were provided for MaterialPropertiesControl. [ control name = \"{self.GetName()}\"]")
48
+
49
+ self.model_part_operation = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, f"control_{self.GetName()}", controlled_model_part_names, False)
50
+ self.model_part: Optional[Kratos.ModelPart] = None
51
+
52
+ self.consider_recursive_property_update = parameters["consider_recursive_property_update"].GetBool()
53
+
54
+ def Initialize(self) -> None:
55
+ self.model_part = self.model_part_operation.GetModelPart()
56
+
57
+ if not KratosOA.OptAppModelPartUtils.CheckModelPartStatus(self.model_part, "element_specific_properties_created"):
58
+ KratosOA.OptimizationUtils.CreateEntitySpecificPropertiesForContainer(self.model_part, self.model_part.Elements, self.consider_recursive_property_update)
59
+ KratosOA.OptAppModelPartUtils.LogModelPartStatus(self.model_part, "element_specific_properties_created")
60
+
61
+ def Check(self) -> None:
62
+ pass
63
+
64
+ def Finalize(self) -> None:
65
+ pass
66
+
67
+ def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]':
68
+ return [self.controlled_physical_variable]
69
+
70
+ def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
71
+ field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, self.controlled_physical_variable)
72
+ field.data[:] = 0.0
73
+ return Kratos.TensorAdaptors.DoubleTensorAdaptor(field, copy=False)
74
+
75
+ def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
76
+ field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, self.controlled_physical_variable)
77
+ field.CollectData()
78
+ return Kratos.TensorAdaptors.DoubleTensorAdaptor(field, copy=False)
79
+
80
+ def MapGradient(self, physical_variable_gradient_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
81
+ keys = physical_variable_gradient_map.keys()
82
+ if len(keys) != 1:
83
+ raise RuntimeError(f"Provided more than required gradient fields for control \"{self.GetName()}\". Following are the variables:\n\t" + "\n\t".join([k.Name() for k in keys]))
84
+ if self.controlled_physical_variable not in keys:
85
+ raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. {self.controlled_physical_variable.Name()} not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys]))
86
+
87
+ physical_gradient = physical_variable_gradient_map[self.controlled_physical_variable]
88
+ if physical_gradient.GetContainer() != self.GetEmptyField().GetContainer():
89
+ raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()} ]")
90
+
91
+ # TODO: Implement filtering mechanisms here
92
+ return physical_variable_gradient_map[self.controlled_physical_variable].Clone()
93
+
94
+ def Update(self, control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool:
95
+ if control_field.GetContainer() != self.GetEmptyField().GetContainer():
96
+ raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()} ]")
97
+
98
+ # TODO: Implement inverse filtering mechanisms here
99
+ # since no filtering is implemented yet, we are checking the unfiltered updates with the filtered updates. This needs to be changed once the
100
+ # filtering mechanisms are implemented.
101
+
102
+ # get the current unfiltered control field
103
+ unfiltered_control_field = self.GetControlField()
104
+
105
+ if numpy.linalg.norm(unfiltered_control_field.data - control_field.data) > 1e-9:
106
+ KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(control_field, self.controlled_physical_variable, copy=False).StoreData()
107
+
108
+ if self.consider_recursive_property_update:
109
+ KratosOA.OptimizationUtils.UpdatePropertiesVariableWithRootValueRecursively(control_field.GetContainer(), self.controlled_physical_variable)
110
+ return True
111
+
112
+ return False
113
+
114
+ def __str__(self) -> str:
115
+ return f"Control [type = {self.__class__.__name__}, name = {self.GetName()}, model part name = {self.model_part.FullName()}, control variable = {self.controlled_physical_variable.Name()}"