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,180 @@
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
+ from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import TimeLogger
10
+ from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
11
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
12
+ from KratosMultiphysics.OptimizationApplication.filtering.filter import Factory as FilterFactory
13
+ from KratosMultiphysics.OptimizationApplication.utilities.opt_projection import CreateProjection
14
+
15
+ def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> Control:
16
+ if not parameters.Has("name"):
17
+ raise RuntimeError(f"ShellThicknessControl instantiation requires a \"name\" in parameters [ parameters = {parameters}].")
18
+ if not parameters.Has("settings"):
19
+ raise RuntimeError(f"ShellThicknessControl instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
20
+
21
+ return ShellThicknessControl(parameters["name"].GetString(), model, parameters["settings"], optimization_problem)
22
+
23
+ class ShellThicknessControl(Control):
24
+ """Shell thickness control
25
+
26
+ This is filtering-based discrete thickness control which parametrizes and controls
27
+ shell elements thickness.
28
+
29
+ """
30
+ def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
31
+ super().__init__(name)
32
+
33
+ self.parameters = parameters
34
+ self.model = model
35
+ self.optimization_problem = optimization_problem
36
+
37
+ default_settings = Kratos.Parameters("""{
38
+ "controlled_model_part_names" : [],
39
+ "filter_settings" : {},
40
+ "output_all_fields" : false,
41
+ "physical_thicknesses" : [],
42
+ "consider_recursive_property_update": false,
43
+ "thickness_projection_settings": {}
44
+ }""")
45
+
46
+ self.parameters.ValidateAndAssignDefaults(default_settings)
47
+
48
+ controlled_model_names_parts = parameters["controlled_model_part_names"].GetStringArray()
49
+ if len(controlled_model_names_parts) == 0:
50
+ raise RuntimeError(f"No model parts were provided for ShellThicknessControl. [ control name = \"{self.GetName()}\"]")
51
+
52
+ self.model_part_operation = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, f"control_{self.GetName()}", self.parameters["controlled_model_part_names"].GetStringArray(), False)
53
+ self.model_part: 'Optional[Kratos.ModelPart]' = None
54
+
55
+ self.filter = FilterFactory(self.model, self.model_part_operation.GetModelPartFullName(), Kratos.THICKNESS, Kratos.Globals.DataLocation.Element, self.parameters["filter_settings"])
56
+
57
+ self.output_all_fields = self.parameters["output_all_fields"].GetBool()
58
+ self.physical_thicknesses = self.parameters["physical_thicknesses"].GetVector()
59
+
60
+ self.thickness_projection = CreateProjection(parameters["thickness_projection_settings"], self.optimization_problem)
61
+
62
+ self.consider_recursive_property_update = parameters["consider_recursive_property_update"].GetBool()
63
+
64
+ num_phys_thick = len(self.physical_thicknesses)
65
+ if num_phys_thick == 0:
66
+ raise RuntimeError("The physical_thicknesses can not be empty, at least min and max should be provided.")
67
+ self.filtered_thicknesses = [i for i, _ in enumerate(self.physical_thicknesses)]
68
+
69
+ def Initialize(self) -> None:
70
+ self.model_part = self.model_part_operation.GetModelPart()
71
+
72
+ if not KratosOA.OptAppModelPartUtils.CheckModelPartStatus(self.model_part, "element_specific_properties_created"):
73
+ KratosOA.OptimizationUtils.CreateEntitySpecificPropertiesForContainer(self.model_part, self.model_part.Elements, self.consider_recursive_property_update)
74
+ KratosOA.OptAppModelPartUtils.LogModelPartStatus(self.model_part, "element_specific_properties_created")
75
+
76
+ # initialize the filter
77
+ self.filter.SetComponentDataView(ComponentDataView(self, self.optimization_problem))
78
+ self.filter.Initialize()
79
+
80
+ # initialize the projections
81
+ self.thickness_projection.SetProjectionSpaces(self.filtered_thicknesses, self.physical_thicknesses)
82
+
83
+ physical_thickness_field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.THICKNESS)
84
+ physical_thickness_field.CollectData()
85
+
86
+ # project backward the uniform physical control field and assign it to the control field
87
+ self.physical_phi_field = self.thickness_projection.ProjectBackward(physical_thickness_field)
88
+
89
+ # take the physical and control field the same
90
+ self.control_phi_field = self.filter.UnfilterField(self.physical_phi_field)
91
+
92
+ # now update the physical thickness field
93
+ self._UpdateAndOutputFields(self.GetEmptyField())
94
+
95
+ def Check(self) -> None:
96
+ self.filter.Check()
97
+
98
+ def Finalize(self) -> None:
99
+ self.filter.Finalize()
100
+
101
+ def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]':
102
+ return [Kratos.THICKNESS]
103
+
104
+ def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
105
+ field = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.THICKNESS)
106
+ field.data[:] = 0.0
107
+ return field
108
+
109
+ def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
110
+ return self.control_phi_field.Clone()
111
+
112
+ def GetPhysicalField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
113
+ physical_thickness_field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.THICKNESS)
114
+ physical_thickness_field.CollectData()
115
+ return physical_thickness_field
116
+
117
+ def MapGradient(self, physical_variable_gradient_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
118
+ with TimeLogger("ShellThicknessControl::MapGradient", None, "Finished",False):
119
+ keys = physical_variable_gradient_map.keys()
120
+ if len(keys) != 1:
121
+ 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]))
122
+ if Kratos.THICKNESS not in keys:
123
+ raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. {Kratos.THICKNESS.Name()} not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys]))
124
+
125
+ physical_gradient = physical_variable_gradient_map[Kratos.THICKNESS]
126
+ if physical_gradient.GetContainer() != self.model_part.Elements:
127
+ raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {physical_gradient.GetModelPart().FullName()} ]")
128
+
129
+ # multiply the physical sensitivity field with projection derivatives
130
+ projected_gradient = Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_gradient)
131
+ projected_gradient.data = physical_gradient.data * self.projection_derivative_field.data
132
+ # now filter the field
133
+ filtered_gradient = self.filter.BackwardFilterIntegratedField(projected_gradient)
134
+
135
+ return filtered_gradient
136
+
137
+ def Update(self, new_control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool:
138
+ if new_control_field.GetContainer() != self.model_part.Elements:
139
+ raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {new_control_field.GetModelPart().FullName()} ]")
140
+
141
+ update = Kratos.TensorAdaptors.DoubleTensorAdaptor(new_control_field)
142
+ update.data[:] = new_control_field.data - self.control_phi_field.data
143
+ if numpy.linalg.norm(update.data) > 1e-15:
144
+ with TimeLogger(self.__class__.__name__, f"Updating {self.GetName()}...", f"Finished updating of {self.GetName()}.",False):
145
+ # update the control thickness field
146
+ self.control_phi_field = new_control_field.Clone()
147
+ # now update the physical field
148
+ self._UpdateAndOutputFields(update)
149
+ self.thickness_projection.Update()
150
+ return True
151
+
152
+ self.thickness_projection.Update()
153
+ return False
154
+
155
+ def _UpdateAndOutputFields(self, update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None:
156
+ # filter the control field
157
+ filtered_thickness_field_update = self.filter.ForwardFilterField(update)
158
+ self.physical_phi_field.data += filtered_thickness_field_update.data
159
+
160
+ # project forward the filtered thickness field
161
+ projected_filtered_thickness_field = self.thickness_projection.ProjectForward(self.physical_phi_field)
162
+ # now update physical field
163
+ KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(projected_filtered_thickness_field, Kratos.THICKNESS, copy=False).StoreData()
164
+ if self.consider_recursive_property_update:
165
+ KratosOA.OptimizationUtils.UpdatePropertiesVariableWithRootValueRecursively(projected_filtered_thickness_field.GetContainer(), Kratos.THICKNESS)
166
+
167
+ # compute and store projection derivatives for consistent filtering of the sensitivities
168
+ self.projection_derivative_field = self.thickness_projection.ForwardProjectionGradient(self.physical_phi_field)
169
+
170
+ # now output the fields
171
+ un_buffered_data = ComponentDataView(self, self.optimization_problem).GetUnBufferedData()
172
+ un_buffered_data.SetValue("physical_thickness", projected_filtered_thickness_field,overwrite=True)
173
+ if self.output_all_fields:
174
+ un_buffered_data.SetValue("filtered_thickness_update", filtered_thickness_field_update, overwrite=True)
175
+ un_buffered_data.SetValue("control_thickness_phi", self.control_phi_field.Clone(), overwrite=True)
176
+ un_buffered_data.SetValue("physical_thickness_phi", self.physical_phi_field.Clone(), overwrite=True)
177
+ un_buffered_data.SetValue("projection_derivative", self.projection_derivative_field.Clone(), overwrite=True)
178
+
179
+ def __str__(self) -> str:
180
+ return f"Control [type = {self.__class__.__name__}, name = {self.GetName()}, model part name = {self.model_part.FullName()}, control variable = {Kratos.THICKNESS.Name()}"
@@ -0,0 +1,205 @@
1
+ # ==============================================================================
2
+ # KratosOptimizationApplication
3
+ #
4
+ # License: BSD License
5
+ # license: OptimizationApplication/license.txt
6
+ #
7
+ # Main authors: Reza Najian Asl, https://github.com/RezaNajian
8
+ #
9
+ # ==============================================================================
10
+
11
+ # additional imports
12
+ import KratosMultiphysics as KM
13
+ import KratosMultiphysics.OptimizationApplication.controls.shape.explicit_vertex_morphing as evm
14
+ import KratosMultiphysics.OptimizationApplication.controls.shape.implicit_vertex_morphing as ivm
15
+ import KratosMultiphysics.OptimizationApplication.controls.thickness.helmholtz_thickness as hlt
16
+ import KratosMultiphysics.OptimizationApplication.controls.material.helmholtz_material as hlm
17
+ import KratosMultiphysics.OptimizationApplication.controls.material.helmholtz_partition as hlp
18
+
19
+ # ==============================================================================
20
+ def CreateController(controls_settings,model,model_parts_controller):
21
+ return ControlsController(controls_settings,model,model_parts_controller)
22
+
23
+ # ==============================================================================
24
+ class ControlsController:
25
+ # --------------------------------------------------------------------------
26
+ def __init__(self,controls_settings,model,model_parts_controller):
27
+
28
+ self.controls_settings = controls_settings
29
+ self.model_parts_controller = model_parts_controller
30
+ self.model = model
31
+
32
+ default_settings = KM.Parameters("""
33
+ {
34
+ "name" : "CONTROL_NAME",
35
+ "type" : "CONTROL_TYPE",
36
+ "settings" : {
37
+ "technique" : "CONTROL_TECHNIQUE",
38
+ "technique_settings" : {},
39
+ "controlling_objects" : []
40
+ }
41
+ }""")
42
+
43
+
44
+ for itr in range(self.controls_settings.size()):
45
+ for key in default_settings.keys():
46
+ if not self.controls_settings[itr].Has(key):
47
+ raise RuntimeError("ControlsController: Required setting '{}' missing in 'control Nr.{}'!".format(key,itr+1))
48
+ self.controls_settings[itr].ValidateAndAssignDefaults(default_settings)
49
+ for key in default_settings["settings"].keys():
50
+ if not self.controls_settings[itr]["settings"].Has(key):
51
+ raise RuntimeError("ControlsController: Required setting '{}' missing in 'settings' of 'control Nr.{}' !".format(key,itr+1))
52
+ self.controls_settings[itr]["settings"].ValidateAndAssignDefaults(default_settings["settings"])
53
+
54
+
55
+ self.supported_control_types_techniques = {"shape":["explicit_vertex_morphing","implicit_vertex_morphing"],"material":["helmholtz_material","helmholtz_partition"],"thickness":["helmholtz_thickness"]}
56
+ # sanity checks
57
+ self.controls_types_vars_dict = {"shape":[],"material":[],"thickness":[]}
58
+ self.controls = {}
59
+ self.controls_type = {}
60
+ self.controls_controlling_objects = {}
61
+ for itr in range(self.controls_settings.size()):
62
+ control_settings = self.controls_settings[itr]
63
+
64
+ # check for name
65
+ control_name = control_settings["name"].GetString()
66
+ if control_name in self.controls.keys():
67
+ raise RuntimeError("ControlsController: Control name {} already exists.".format(control_name))
68
+ # check control type
69
+ control_type = control_settings["type"].GetString()
70
+ if not control_type in self.supported_control_types_techniques.keys():
71
+ raise RuntimeError("ControlsController: control type '{}' in control {} is not supported!, we support {} ".format(control_type,control_name,self.supported_control_types_techniques))
72
+ self.controls_type[control_name] = control_type
73
+ # check control technique
74
+ control_technique = control_settings["settings"]["technique"].GetString()
75
+ if not control_technique in self.supported_control_types_techniques[control_type]:
76
+ raise RuntimeError("ControlsController: control technique '{}' for control type {} in control {} is not supported!, we support {}".format(control_technique,control_type,control_name,self.supported_control_types_techniques))
77
+
78
+ # check for repetitious control over variables
79
+ control_controlling_objects_list = control_settings["settings"]["controlling_objects"].GetStringArray()
80
+ control_controlling_objects_list_set = set(control_controlling_objects_list)
81
+ if len(control_controlling_objects_list_set) != len(control_controlling_objects_list):
82
+ raise RuntimeError("ControlsController: control '{}' has duplicated control variables!".format(control_name))
83
+ if control_controlling_objects_list_set.issubset(set(self.controls_types_vars_dict[control_type])):
84
+ raise RuntimeError("ControlsController: there are duplicated {} control over {}!".format(control_type,control_controlling_objects_list))
85
+ if control_name in self.controls.keys():
86
+ raise RuntimeError("ControlsController: control name {} is duplicated !",control_name)
87
+ self.controls_controlling_objects[control_name] = control_controlling_objects_list
88
+
89
+ # check if root model parts exist
90
+ self.model_parts_controller.CheckIfRootModelPartsExist(control_controlling_objects_list,True)
91
+
92
+ # now checks passed and create the control
93
+ if control_type == "shape":
94
+ if control_technique == "explicit_vertex_morphing":
95
+ control = evm.ExplicitVertexMorphing(control_name,model,control_settings["settings"])
96
+ elif control_technique == "implicit_vertex_morphing":
97
+ control = ivm.ImplicitVertexMorphing(control_name,model,control_settings["settings"])
98
+ elif control_type == "thickness":
99
+ if control_technique == "helmholtz_thickness":
100
+ control = hlt.HelmholtzThickness(control_name,model,control_settings["settings"])
101
+ elif control_type == "material":
102
+ if control_technique == "helmholtz_material":
103
+ control = hlm.HelmholtzMaterial(control_name,model,control_settings["settings"])
104
+ elif control_technique == "helmholtz_partition":
105
+ control = hlp.HelmholtzPartition(control_name,model,control_settings["settings"])
106
+
107
+ self.controls[control_name] = control
108
+ self.controls_types_vars_dict[control_type].extend(control_controlling_objects_list)
109
+
110
+ # --------------------------------------------------------------------------
111
+ def Initialize(self):
112
+ for key,value in self.controls.items():
113
+ value.Initialize()
114
+
115
+ # --------------------------------------------------------------------------
116
+ def ControlMapFirstDerivative(self,control_name,derivative_name,mapped_derivative_name,raise_error=True):
117
+ if raise_error:
118
+ if not control_name in self.controls.keys():
119
+ raise RuntimeError("ControlsController:ControlMapFirstDerivative: Control {} does not exist.".format(control_name))
120
+
121
+ self.controls[control_name].MapFirstDerivative(derivative_name,mapped_derivative_name)
122
+
123
+ # --------------------------------------------------------------------------
124
+ def CheckIfControlExists(self,control_name,raise_error=True):
125
+ if not control_name in self.controls.keys():
126
+ if raise_error:
127
+ raise RuntimeError("ControlsController:CheckIfControlExists: Control {} does not exist.".format(control_name))
128
+ else:
129
+ return False
130
+ else:
131
+ return True
132
+ # --------------------------------------------------------------------------
133
+ def CheckIfControlsExist(self,controls_name,raise_error=True):
134
+ if type(controls_name) is not list:
135
+ raise RuntimeError("ControlsController:CheckIfControlsExist requires list of control names")
136
+
137
+ if_exist = True
138
+ for control_name in controls_name:
139
+ if not control_name in self.controls.keys():
140
+ if raise_error:
141
+ raise RuntimeError("ControlsController:CheckIfControlsExist: Control {} does not exist!".format(control_name))
142
+ else:
143
+ if_exist = False
144
+ break
145
+ return if_exist
146
+
147
+ # --------------------------------------------------------------------------
148
+ def GetControlType(self,control_name,raise_error=True):
149
+ if not control_name in self.controls_type.keys():
150
+ if raise_error:
151
+ raise RuntimeError("ControlsController:GetControlType: Control {} does not exist.".format(control_name))
152
+ else:
153
+ return self.controls_type[control_name]
154
+ # --------------------------------------------------------------------------
155
+ def GetControlVariableName(self,control_name,raise_error=True):
156
+ if not control_name in self.controls_type.keys():
157
+ if raise_error:
158
+ raise RuntimeError("ControlsController:GetControlVariableName: Control {} does not exist.".format(control_name))
159
+ else:
160
+ return self.controls[control_name].GetVariableName()
161
+ # --------------------------------------------------------------------------
162
+ def GetControlUpdateName(self,control_name,raise_error=True):
163
+ if not control_name in self.controls_type.keys():
164
+ if raise_error:
165
+ raise RuntimeError("ControlsController:GetControlUpdateName: Control {} does not exist.".format(control_name))
166
+ else:
167
+ return self.controls[control_name].GetUpdateName()
168
+ # --------------------------------------------------------------------------
169
+ def GetControlOutputNames(self,control_name,raise_error=True):
170
+ if not control_name in self.controls_type.keys():
171
+ if raise_error:
172
+ raise RuntimeError("ControlsController:GetControlOutputNames: Control {} does not exist.".format(control_name))
173
+ else:
174
+ return self.controls[control_name].GetOutputNames()
175
+ # --------------------------------------------------------------------------
176
+ def GetControlControllingObjects(self,control_name,raise_error=True):
177
+ if raise_error:
178
+ if not control_name in self.controls_controlling_objects.keys():
179
+ raise RuntimeError("ControlsController:GetControlControllingObjects: Control {} does not exist.".format(control_name))
180
+
181
+ return self.controls[control_name].GetControllingObjects()
182
+
183
+ # --------------------------------------------------------------------------
184
+ def MapControlFirstDerivative(self, control_name, derivative_variable_name, mapped_derivative_variable_name, raise_error=True):
185
+ if raise_error:
186
+ if not control_name in self.controls_controlling_objects.keys():
187
+ raise RuntimeError("ControlsController:MapControlFirstDerivative: Control {} does not exist.".format(control_name))
188
+
189
+ self.controls[control_name].MapFirstDerivative(derivative_variable_name,mapped_derivative_variable_name)
190
+
191
+ # --------------------------------------------------------------------------
192
+ def UpdateControl(self, control_name, raise_error=True):
193
+ if raise_error:
194
+ if not control_name in self.controls_controlling_objects.keys():
195
+ raise RuntimeError("ControlsController:UpdateControl: Control {} does not exist.".format(control_name))
196
+
197
+ self.controls[control_name].Update()
198
+
199
+ # --------------------------------------------------------------------------
200
+ def ComputeControl(self, control_name, raise_error=True):
201
+ if raise_error:
202
+ if not control_name in self.controls_controlling_objects.keys():
203
+ raise RuntimeError("ControlsController:ComputeControl: Control {} does not exist.".format(control_name))
204
+
205
+ self.controls[control_name].Compute()
@@ -0,0 +1,98 @@
1
+ import typing
2
+ import numpy
3
+ import KratosMultiphysics as Kratos
4
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
5
+ from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
6
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentHavingDataByFullName
7
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentValueByFullName
8
+ from KratosMultiphysics.OptimizationApplication.convergence_criteria.convergence_criterion import ConvergenceCriterion
9
+ from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator
10
+
11
+ def Factory(_: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ConvergenceCriterion:
12
+ if not parameters.Has("settings"):
13
+ raise RuntimeError(f"AvgAbsImprovementConvCriterion instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
14
+ return AvgAbsImprovementConvCriterion(parameters["settings"], optimization_problem)
15
+
16
+ class AvgAbsImprovementConvCriterion(ConvergenceCriterion):
17
+ """
18
+ AvgAbsImprovementConvCriterion is a convergence criterion for optimization algorithms that checks
19
+ whether the average absolute improvement of a tracked value over a specified number of iterations
20
+ falls below a given tolerance.
21
+ """
22
+ @classmethod
23
+ def GetDefaultParameters(cls):
24
+ return Kratos.Parameters("""{
25
+ "component_name": "algorithm",
26
+ "value_name" : "std_obj_value",
27
+ "tracked_iter" : 5,
28
+ "tolerance" : 1e-6
29
+ }""")
30
+
31
+ def __init__(self, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
32
+ parameters.ValidateAndAssignDefaults(self.GetDefaultParameters())
33
+
34
+ self.__component_name = parameters["component_name"].GetString()
35
+ self.__value_name = parameters["value_name"].GetString()
36
+ self.__tolerance = parameters["tolerance"].GetDouble()
37
+ self.__tracked_iter = parameters["tracked_iter"].GetInt()
38
+ self.__optimization_problem = optimization_problem
39
+ self.__component_data_view: 'typing.Optional[ComponentDataView]' = None
40
+
41
+ if self.__value_name.find(":") == -1:
42
+ # not found where the data location. So the default for value names
43
+ # will be buffered (i.e. historical). So appending it
44
+ self.__value_name += ":historical"
45
+
46
+ if self.__tolerance < 0.0:
47
+ raise RuntimeError(f"Tolerance should be non-negative [ tolerance = {self.__tolerance} ].")
48
+
49
+ if self.__tracked_iter <= 2:
50
+ raise RuntimeError(f"The tracked_iter value must be greater than 2 [ tracked_iter = {self.__tracked_iter} ].")
51
+
52
+ self.__abs_value_change = numpy.zeros(self.__tracked_iter - 1)
53
+
54
+ def Initialize(self):
55
+ component = GetComponentHavingDataByFullName(self.__component_name, self.__optimization_problem)
56
+ self.__component_data_view = ComponentDataView(component, self.__optimization_problem)
57
+
58
+ @time_decorator()
59
+ def IsConverged(self) -> bool:
60
+ step = self.__optimization_problem.GetStep()
61
+ value = GetComponentValueByFullName(self.__component_data_view, self.__value_name)
62
+
63
+ if not isinstance(value, float) and not isinstance(value, int):
64
+ raise RuntimeError(f"The value represented by {self.__value_name} is not a floating or int value.")
65
+
66
+ if step == 0:
67
+ self.__init_value = value
68
+ self.__value = 0.0
69
+ self.__conv = False
70
+ elif step > 0:
71
+ prev_value = GetComponentValueByFullName(self.__component_data_view, self.__value_name, 1)
72
+ self.__abs_value_change[step % (self.__tracked_iter - 1)] = ((value - prev_value) / self.__init_value)
73
+
74
+ if step >= self.__tracked_iter - 1:
75
+ self.__value = numpy.abs(numpy.sum(self.__abs_value_change)) / (self.__tracked_iter - 1)
76
+ self.__conv = self.__value <= self.__tolerance
77
+ else:
78
+ self.__value = numpy.abs(numpy.sum(self.__abs_value_change)) / step
79
+ self.__conv = False
80
+
81
+ self.__component_data_view.GetBufferedData().SetValue(f"{self.__value_name.split(':')[0]}_avg_abs_{self.__tracked_iter}_itr", self.__value)
82
+
83
+ return self.__conv
84
+
85
+ def Finalize(self):
86
+ pass
87
+
88
+ def GetInfo(self) -> 'list[tuple[str, typing.Union[int, float, str]]]':
89
+ info = [
90
+ ('type' , 'avg_abs_improvement_conv_criterion'),
91
+ ('avg_value' , self.__value),
92
+ ('tracked_iter' , self.__tracked_iter),
93
+ ('tolerance' , self.__tolerance),
94
+ ('component_name', self.__component_name),
95
+ ('value_name' , self.__value_name),
96
+ ('status' , str("converged" if self.__conv else "not converged"))
97
+ ]
98
+ return info
@@ -0,0 +1,87 @@
1
+ import typing
2
+ import KratosMultiphysics as Kratos
3
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
4
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import OptimizationComponentFactory
5
+ from KratosMultiphysics.OptimizationApplication.convergence_criteria.convergence_criterion import ConvergenceCriterion
6
+
7
+ def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ConvergenceCriterion:
8
+ if not parameters.Has("settings"):
9
+ raise RuntimeError(f"CombinedConvCriterion instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
10
+ return CombinedConvCriterion(model, parameters["settings"], optimization_problem)
11
+
12
+ class CombinedConvCriterion(ConvergenceCriterion):
13
+ """
14
+ CombinedConvCriterion is a convergence criterion that combines multiple sub-criteria using a logical operator ("and" or "or").
15
+ It evaluates convergence by applying the specified operator to the results of its sub-criteria.
16
+
17
+ Args:
18
+ model (Kratos.Model): The Kratos model instance.
19
+ parameters (Kratos.Parameters): Parameters specifying the operator and the list of sub-criteria.
20
+ optimization_problem (OptimizationProblem): The optimization problem instance.
21
+
22
+ Raises:
23
+ RuntimeError: If an unsupported operator is specified or if the list of sub-criteria is empty.
24
+ """
25
+ @classmethod
26
+ def GetDefaultParameters(cls):
27
+ return Kratos.Parameters("""{
28
+ "operator" : "",
29
+ "list_of_convergence_criteria": []
30
+ }""")
31
+
32
+ def __init__(self, model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
33
+ default_params = self.GetDefaultParameters()
34
+
35
+ parameters.ValidateAndAssignDefaults(default_params)
36
+
37
+ self.__operator = parameters["operator"].GetString()
38
+ if self.__operator not in ["and", "or"]:
39
+ raise RuntimeError(f"Unsupported operator = \"{self.__operator}\". Followings are supported:\n\tand\n\tor")
40
+
41
+ self.__list_of_convergence_criteria: 'list[ConvergenceCriterion]' = []
42
+ default_sub_conv_settings = Kratos.Parameters("""{
43
+ "type" : "",
44
+ "module" : "KratosMultiphysics.OptimizationApplication.convergence_criteria",
45
+ "settings": {}
46
+ }""")
47
+ for sub_convergence_params in parameters["list_of_convergence_criteria"].values():
48
+ sub_convergence_params.ValidateAndAssignDefaults(default_sub_conv_settings)
49
+ self.__list_of_convergence_criteria.append(OptimizationComponentFactory(model, sub_convergence_params, optimization_problem))
50
+
51
+ def Add(self, convergence_criterion: ConvergenceCriterion) -> None:
52
+ self.__list_of_convergence_criteria.append(convergence_criterion)
53
+
54
+ def Initialize(self):
55
+ if len(self.__list_of_convergence_criteria) == 0:
56
+ raise RuntimeError("An empty combined convergence criteria is not allowed.")
57
+
58
+ for conv in self.__list_of_convergence_criteria:
59
+ conv.Initialize()
60
+
61
+ def IsConverged(self) -> bool:
62
+ if self.__operator == "and":
63
+ self.__conv = all([conv.IsConverged() for conv in self.__list_of_convergence_criteria])
64
+ elif self.__operator == "or":
65
+ self.__conv = any([conv.IsConverged() for conv in self.__list_of_convergence_criteria])
66
+ return self.__conv
67
+
68
+ def Finalize(self):
69
+ for conv in self.__list_of_convergence_criteria:
70
+ conv.Finalize()
71
+
72
+ def GetInfo(self) -> 'list[tuple[str, typing.Union[int, float, str]]]':
73
+ info = []
74
+ if len(self.__list_of_convergence_criteria) > 1:
75
+ info.append(("(", ""))
76
+
77
+ info.extend(self.__list_of_convergence_criteria[0].GetInfo())
78
+
79
+ for conv in self.__list_of_convergence_criteria[1:]:
80
+ info.append((f"--- {self.__operator} ---", ""))
81
+ info.extend(conv.GetInfo())
82
+
83
+ if len(self.__list_of_convergence_criteria) > 1:
84
+ info.append((") -->", str("converged" if self.__conv else "not converged")))
85
+
86
+ return info
87
+
@@ -0,0 +1,68 @@
1
+ import typing
2
+ import KratosMultiphysics as Kratos
3
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
4
+ from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
5
+ from KratosMultiphysics.OptimizationApplication.convergence_criteria.convergence_criterion import ConvergenceCriterion
6
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentHavingDataByFullName
7
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentValueByFullName
8
+ from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator
9
+
10
+ def Factory(_: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ConvergenceCriterion:
11
+ if not parameters.Has("settings"):
12
+ raise RuntimeError(f"ConstraintConvCriterion instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
13
+ return ConstraintConvCriterion(parameters["settings"], optimization_problem)
14
+
15
+ class ConstraintConvCriterion(ConvergenceCriterion):
16
+ """
17
+ ConstraintConvCriterion is a convergence criterion for optimization problems, specifically designed to check the convergence of constraints.
18
+
19
+ This class checks whether a specified value associated with a component in the optimization problem has reached a given tolerance.
20
+ """
21
+ @classmethod
22
+ def GetDefaultParameters(cls):
23
+ return Kratos.Parameters("""{
24
+ "component_name": "",
25
+ "value_name" : "std_value",
26
+ "tolerance" : 0.0
27
+ }""")
28
+
29
+ def __init__(self, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
30
+ parameters.ValidateAndAssignDefaults(self.GetDefaultParameters())
31
+
32
+
33
+ self.__component_name = parameters["component_name"].GetString()
34
+ self.__value_name = parameters["value_name"].GetString()
35
+ self.__tolerance = parameters["tolerance"].GetDouble()
36
+ self.__optimization_problem = optimization_problem
37
+
38
+ if self.__value_name.find(":") == -1:
39
+ # not found where the data location. So the default for value names
40
+ # will be buffered (i.e. historical). So appending it
41
+ self.__value_name += ":historical"
42
+
43
+ if self.__tolerance < 0.0:
44
+ raise RuntimeError(f"Tolerance should be non-negative [ tolerance = {self.__tolerance} ].")
45
+
46
+ def Initialize(self):
47
+ component = GetComponentHavingDataByFullName(self.__component_name, self.__optimization_problem)
48
+ self.__component_data_view = ComponentDataView(component, self.__optimization_problem)
49
+
50
+ @time_decorator()
51
+ def IsConverged(self) -> bool:
52
+ self.__value = GetComponentValueByFullName(self.__component_data_view, self.__value_name)
53
+ self.__conv = self.__value <= self.__tolerance
54
+ return self.__conv
55
+
56
+ def Finalize(self):
57
+ pass
58
+
59
+ def GetInfo(self) -> 'list[tuple[str, typing.Union[int, float, str]]]':
60
+ info = [
61
+ ("type" , "constraint_conv_criterion"),
62
+ ("value" , self.__value),
63
+ ("tolerance" , self.__tolerance),
64
+ ('component_name', self.__component_name),
65
+ ('value_name' , self.__value_name),
66
+ ("status", str("converged" if self.__conv else "not converged"))
67
+ ]
68
+ return info