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.
- KratosMultiphysics/.libs/KratosOptimizationApplication.so +0 -0
- KratosMultiphysics/.libs/libKratosOptimizationCore.dylib +0 -0
- KratosMultiphysics/OptimizationApplication/__init__.py +19 -0
- KratosMultiphysics/OptimizationApplication/algorithms/NLOPT_algorithms.py +255 -0
- KratosMultiphysics/OptimizationApplication/algorithms/SciPy_algorithms.py +154 -0
- KratosMultiphysics/OptimizationApplication/algorithms/__init__.py +0 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm.py +78 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_adam.py +68 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_base.py +393 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_gradient_projection.py +355 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_momentum_relaxed_gradient_projection.py +70 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_nesterov_accelarated_gradient.py +60 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_relaxed_gradient_projection.py +263 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_steepest_descent.py +205 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_NLOPT_constraint.py +194 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_NLOPT_objective.py +191 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_SciPy_constraint.py +123 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_SciPy_objective.py +148 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_constraint.py +180 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_objective.py +133 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_rgp_constraint.py +268 -0
- KratosMultiphysics/OptimizationApplication/analyses_controller.py +75 -0
- KratosMultiphysics/OptimizationApplication/controls/control.py +123 -0
- KratosMultiphysics/OptimizationApplication/controls/external_response_function_control.py +149 -0
- KratosMultiphysics/OptimizationApplication/controls/master_control.py +198 -0
- KratosMultiphysics/OptimizationApplication/controls/material/material_properties_control.py +115 -0
- KratosMultiphysics/OptimizationApplication/controls/material/simp_control.py +229 -0
- KratosMultiphysics/OptimizationApplication/controls/shape/vertex_morphing_shape_control.py +289 -0
- KratosMultiphysics/OptimizationApplication/controls/thickness/shell_thickness_control.py +180 -0
- KratosMultiphysics/OptimizationApplication/controls_controller.py +205 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/avg_abs_improvement_conv_criterion.py +98 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/combined_conv_criterion.py +87 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/constraint_conv_criterion.py +68 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/convergence_criterion.py +26 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/l2_conv_criterion.py +77 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/magnitude_reduction_conv_criterion.py +85 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/max_iter_conv_criterion.py +48 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/patience_conv_criterion.py +116 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/target_value_conv_criterion.py +64 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/execution_policy.py +46 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/execution_policy_decorator.py +67 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/independent_analysis_execution_policy.py +78 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/kratos_analysis_execution_policy.py +137 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/stepping_analysis_execution_policy.py +88 -0
- KratosMultiphysics/OptimizationApplication/filtering/explicit_filter.py +124 -0
- KratosMultiphysics/OptimizationApplication/filtering/filter.py +188 -0
- KratosMultiphysics/OptimizationApplication/filtering/filter_utils.py +55 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_analysis.py +139 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_scalar_solver.py +39 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_shape_solver.py +67 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_solver_base.py +275 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_vector_solver.py +39 -0
- KratosMultiphysics/OptimizationApplication/filtering/implicit_filter.py +192 -0
- KratosMultiphysics/OptimizationApplication/filtering/python_solvers_wrapper_implicit_filters.py +56 -0
- KratosMultiphysics/OptimizationApplication/model_part_controllers/connectivity_preserving_model_part_controller.py +72 -0
- KratosMultiphysics/OptimizationApplication/model_part_controllers/external_response_function_model_part_controller.py +110 -0
- KratosMultiphysics/OptimizationApplication/model_part_controllers/mdpa_model_part_controller.py +44 -0
- KratosMultiphysics/OptimizationApplication/model_part_controllers/model_part_controller.py +19 -0
- KratosMultiphysics/OptimizationApplication/model_parts_controller.py +92 -0
- KratosMultiphysics/OptimizationApplication/optimization_analysis.py +146 -0
- KratosMultiphysics/OptimizationApplication/optimizations_controller.py +223 -0
- KratosMultiphysics/OptimizationApplication/optimizer.py +61 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_ascii_output_process.py +212 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_field_output_process.py +122 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_graph_output_process.py +184 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_hdf5_output_process.py +84 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_vtu_output_process.py +94 -0
- KratosMultiphysics/OptimizationApplication/processes/spatial_statistics_computation_process.py +81 -0
- KratosMultiphysics/OptimizationApplication/responses/__init__.py +0 -0
- KratosMultiphysics/OptimizationApplication/responses/additive_manufacturing_responses.py +410 -0
- KratosMultiphysics/OptimizationApplication/responses/analysis_based_response_function_factory.py +14 -0
- KratosMultiphysics/OptimizationApplication/responses/analysis_free_response_function_factory.py +14 -0
- KratosMultiphysics/OptimizationApplication/responses/base_response.py +66 -0
- KratosMultiphysics/OptimizationApplication/responses/binary_operator_response_function.py +103 -0
- KratosMultiphysics/OptimizationApplication/responses/combined_response_function.py +127 -0
- KratosMultiphysics/OptimizationApplication/responses/discrete_value_residual_response_function.py +131 -0
- KratosMultiphysics/OptimizationApplication/responses/evaluation_response_function.py +68 -0
- KratosMultiphysics/OptimizationApplication/responses/external_response_function.py +87 -0
- KratosMultiphysics/OptimizationApplication/responses/geometric_centroid_deviation_response_function.py +97 -0
- KratosMultiphysics/OptimizationApplication/responses/linear_strain_energy_response_function.py +72 -0
- KratosMultiphysics/OptimizationApplication/responses/literal_value_response_function.py +33 -0
- KratosMultiphysics/OptimizationApplication/responses/log_response_function.py +47 -0
- KratosMultiphysics/OptimizationApplication/responses/mass_response_function.py +71 -0
- KratosMultiphysics/OptimizationApplication/responses/response_function.py +126 -0
- KratosMultiphysics/OptimizationApplication/responses/response_routine.py +158 -0
- KratosMultiphysics/OptimizationApplication/responses/structural_responses.py +335 -0
- KratosMultiphysics/OptimizationApplication/responses_controller.py +390 -0
- KratosMultiphysics/OptimizationApplication/utilities/buffered_dict.py +399 -0
- KratosMultiphysics/OptimizationApplication/utilities/component_data_view.py +74 -0
- KratosMultiphysics/OptimizationApplication/utilities/helper_utilities.py +40 -0
- KratosMultiphysics/OptimizationApplication/utilities/logger_utilities.py +222 -0
- KratosMultiphysics/OptimizationApplication/utilities/model_part_utilities.py +117 -0
- KratosMultiphysics/OptimizationApplication/utilities/opt_line_search.py +173 -0
- KratosMultiphysics/OptimizationApplication/utilities/opt_projection.py +191 -0
- KratosMultiphysics/OptimizationApplication/utilities/optimization_problem.py +237 -0
- KratosMultiphysics/OptimizationApplication/utilities/optimization_problem_utilities.py +237 -0
- KratosMultiphysics/OptimizationApplication/utilities/response_utilities.py +249 -0
- KratosMultiphysics/OptimizationApplication/utilities/timer.py +45 -0
- KratosMultiphysics/OptimizationApplication/utilities/union_utilities.py +6 -0
- kratosoptimizationapplication-10.4.4.dist-info/METADATA +25 -0
- kratosoptimizationapplication-10.4.4.dist-info/RECORD +106 -0
- kratosoptimizationapplication-10.4.4.dist-info/WHEEL +6 -0
- kratosoptimizationapplication.dylibs/libKratosCore.dylib +4 -0
- kratosoptimizationapplication.dylibs/libgcc_s.1.1.dylib +0 -0
- kratosoptimizationapplication.dylibs/libgomp.1.dylib +0 -0
- 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
|