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,191 @@
|
|
|
1
|
+
import KratosMultiphysics as Kratos
|
|
2
|
+
import KratosMultiphysics.OptimizationApplication as KratosOA
|
|
3
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
|
|
4
|
+
from KratosMultiphysics.OptimizationApplication.responses.response_routine import ResponseRoutine
|
|
5
|
+
from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl
|
|
6
|
+
from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
|
|
7
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import DictLogger
|
|
8
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import TimeLogger
|
|
9
|
+
from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import CallOnAll
|
|
10
|
+
from KratosMultiphysics.OptimizationApplication.utilities.response_utilities import EvaluateResponseExpression
|
|
11
|
+
from KratosMultiphysics.kratos_utilities import IssueDeprecationWarning
|
|
12
|
+
import numpy
|
|
13
|
+
import datetime
|
|
14
|
+
|
|
15
|
+
class StandardizedNLOPTObjective(ResponseRoutine):
|
|
16
|
+
"""Standardized objective response function
|
|
17
|
+
|
|
18
|
+
This class transformed a user-given optimization problem into the standard format.
|
|
19
|
+
Supported objective types:
|
|
20
|
+
"minimization",
|
|
21
|
+
"maximization"
|
|
22
|
+
|
|
23
|
+
"""
|
|
24
|
+
def __init__(self, parameters: Kratos.Parameters, master_control: MasterControl, optimization_problem: OptimizationProblem, required_buffer_size: int = 2):
|
|
25
|
+
# backward compatibility
|
|
26
|
+
if parameters.Has("response_name"):
|
|
27
|
+
IssueDeprecationWarning(self.__class__.__name__, "\"response_name\" is deprecated. Please use \"response_expression\".")
|
|
28
|
+
parameters.AddString("response_expression", parameters["response_name"].GetString())
|
|
29
|
+
parameters.RemoveValue("response_name")
|
|
30
|
+
|
|
31
|
+
default_parameters = Kratos.Parameters("""{
|
|
32
|
+
"response_expression": "",
|
|
33
|
+
"type" : "",
|
|
34
|
+
"scaling" : 1.0
|
|
35
|
+
}""")
|
|
36
|
+
parameters.ValidateAndAssignDefaults(default_parameters)
|
|
37
|
+
|
|
38
|
+
response = EvaluateResponseExpression(parameters["response_expression"].GetString(), optimization_problem)
|
|
39
|
+
|
|
40
|
+
super().__init__(master_control, response)
|
|
41
|
+
|
|
42
|
+
if required_buffer_size < 2:
|
|
43
|
+
raise RuntimeError(f"Standardized objective requires 2 as minimum buffer size. [ response name = {self.GetReponse().GetName()} ]")
|
|
44
|
+
|
|
45
|
+
component_data_view = ComponentDataView(response, optimization_problem)
|
|
46
|
+
component_data_view.SetDataBuffer(required_buffer_size)
|
|
47
|
+
|
|
48
|
+
self.__optimization_problem = optimization_problem
|
|
49
|
+
self.__buffered_data = component_data_view.GetBufferedData()
|
|
50
|
+
self.__unbuffered_data = component_data_view.GetUnBufferedData()
|
|
51
|
+
|
|
52
|
+
scaling = parameters["scaling"].GetDouble()
|
|
53
|
+
if scaling < 0.0:
|
|
54
|
+
raise RuntimeError(f"Scaling should be always positive [ given scale = {scaling}]")
|
|
55
|
+
|
|
56
|
+
self.__objective_type = parameters["type"].GetString()
|
|
57
|
+
if self.__objective_type == "minimization":
|
|
58
|
+
self.__scaling = scaling
|
|
59
|
+
elif self.__objective_type == "maximization":
|
|
60
|
+
self.__scaling = -scaling
|
|
61
|
+
else:
|
|
62
|
+
raise RuntimeError(f"Requesting unsupported type {self.__objective_type} for objective response function. Supported types are: \n\tminimization\n\tmaximization")
|
|
63
|
+
|
|
64
|
+
def GetInitialValue(self) -> float:
|
|
65
|
+
if self.__unbuffered_data.HasValue("initial_value"):
|
|
66
|
+
return self.__unbuffered_data["initial_value"] * self.__scaling
|
|
67
|
+
else:
|
|
68
|
+
raise RuntimeError(f"Response value for {self.GetReponse().GetName()} is not calculated yet.")
|
|
69
|
+
|
|
70
|
+
def CalculateStandardizedValueAndGradients(self, control_field: numpy.ndarray, gradient_field: numpy.ndarray, save_value: bool = True) -> float:
|
|
71
|
+
if self.UpdateMasterControlAndLogFields(control_field) or self.__optimization_problem.GetStep()==0:
|
|
72
|
+
with TimeLogger(f"CalculateStandardizedValueAndGradients {self.GetReponse().GetName()} value", None, "Finished"):
|
|
73
|
+
|
|
74
|
+
response_value = self.GetReponse().CalculateValue()
|
|
75
|
+
|
|
76
|
+
if not self.__unbuffered_data.HasValue("initial_value"):
|
|
77
|
+
self.__unbuffered_data["initial_value"] = response_value
|
|
78
|
+
|
|
79
|
+
if self.__buffered_data.HasValue("value"): del self.__buffered_data["value"]
|
|
80
|
+
self.__buffered_data["value"] = response_value
|
|
81
|
+
|
|
82
|
+
# log values
|
|
83
|
+
if save_value:
|
|
84
|
+
self.LogValues()
|
|
85
|
+
|
|
86
|
+
# print the info
|
|
87
|
+
DictLogger("Objective info",self.GetInfo())
|
|
88
|
+
|
|
89
|
+
# compute standardization factor
|
|
90
|
+
self.standardization_factor = self.__scaling
|
|
91
|
+
if abs(self.__unbuffered_data["initial_value"])>1e-15:
|
|
92
|
+
self.standardization_factor /= abs(self.__unbuffered_data["initial_value"])
|
|
93
|
+
self.standardized_response_value = self.standardization_factor * response_value
|
|
94
|
+
|
|
95
|
+
# compute gradients
|
|
96
|
+
if gradient_field.size > 0:
|
|
97
|
+
self.gradient_combined_tensor_adaptor = self.CalculateGradient()
|
|
98
|
+
# save gradients
|
|
99
|
+
if save_value:
|
|
100
|
+
self.LogGradientFields()
|
|
101
|
+
|
|
102
|
+
if gradient_field.size > 0:
|
|
103
|
+
gradient_field[:] = self.standardization_factor * self.gradient_combined_tensor_adaptor.data.reshape(-1)
|
|
104
|
+
|
|
105
|
+
return self.standardized_response_value
|
|
106
|
+
|
|
107
|
+
def GetValue(self, step_index: int = 0) -> float:
|
|
108
|
+
return self.__buffered_data.GetValue("value", step_index)
|
|
109
|
+
|
|
110
|
+
def GetStandardizedValue(self, step_index: int = 0) -> float:
|
|
111
|
+
return self.GetValue(step_index) * self.__scaling
|
|
112
|
+
|
|
113
|
+
def GetRelativeChange(self) -> float:
|
|
114
|
+
if self.__optimization_problem.GetStep() > 0:
|
|
115
|
+
return self.GetStandardizedValue() / self.GetStandardizedValue(1) - 1.0 if abs(self.GetStandardizedValue(1)) > 1e-12 else self.GetStandardizedValue()
|
|
116
|
+
else:
|
|
117
|
+
return 0.0
|
|
118
|
+
|
|
119
|
+
def GetAbsoluteChange(self) -> float:
|
|
120
|
+
if self.__optimization_problem.GetStep() > 0:
|
|
121
|
+
return self.GetStandardizedValue() / self.GetInitialValue() - 1.0 if abs(self.GetInitialValue()) > 1e-12 else self.GetStandardizedValue()
|
|
122
|
+
else:
|
|
123
|
+
return 0.0
|
|
124
|
+
|
|
125
|
+
def GetInfo(self) -> dict:
|
|
126
|
+
info = {
|
|
127
|
+
"name": self.GetReponse().GetName(),
|
|
128
|
+
"type": self.__objective_type,
|
|
129
|
+
"value": self.GetValue(),
|
|
130
|
+
"abs_change [%]": self.GetAbsoluteChange() * 100.0,
|
|
131
|
+
"rel_change [%]": self.GetRelativeChange() * 100.0
|
|
132
|
+
}
|
|
133
|
+
return info
|
|
134
|
+
|
|
135
|
+
def LogValues(self) -> None:
|
|
136
|
+
values_info = self.GetInfo()
|
|
137
|
+
if self.__buffered_data.HasValue("rel_change [%]"): del self.__buffered_data["rel_change [%]"]
|
|
138
|
+
self.__buffered_data["rel_change [%]"] = values_info["rel_change [%]"]
|
|
139
|
+
if self.__buffered_data.HasValue("abs_change [%]"): del self.__buffered_data["abs_change [%]"]
|
|
140
|
+
self.__buffered_data["abs_change [%]"] = values_info["abs_change [%]"]
|
|
141
|
+
|
|
142
|
+
def LogGradientFields(self) -> None:
|
|
143
|
+
# save the physical gradients for post processing in unbuffered data container.
|
|
144
|
+
for physical_var, physical_gradient in self.GetRequiredPhysicalGradients().items():
|
|
145
|
+
variable_name = f"d{self.GetReponse().GetName()}_d{physical_var.Name()}"
|
|
146
|
+
for physical_gradient_ta in physical_gradient.GetTensorAdaptors():
|
|
147
|
+
if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name]
|
|
148
|
+
# cloning is a cheap operation, it only moves underlying pointers
|
|
149
|
+
# does not create additional memory.
|
|
150
|
+
self.__unbuffered_data[variable_name] = physical_gradient_ta.Clone()
|
|
151
|
+
|
|
152
|
+
# save the filtered gradients for post processing in unbuffered data container.
|
|
153
|
+
for gradient_ta, control in zip(self.gradient_combined_tensor_adaptor.GetTensorAdaptors(), self.GetMasterControl().GetListOfControls()):
|
|
154
|
+
variable_name = f"d{self.GetReponse().GetName()}_d{control.GetName()}"
|
|
155
|
+
if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name]
|
|
156
|
+
# cloning is a cheap operation, it only moves underlying pointers
|
|
157
|
+
# does not create additional memory.
|
|
158
|
+
self.__unbuffered_data[variable_name] = gradient_ta.Clone()
|
|
159
|
+
|
|
160
|
+
def LogOptimizationStep(self) -> None:
|
|
161
|
+
now = datetime.datetime.now()
|
|
162
|
+
now_str = now.strftime("%Y-%m-%d %H:%M:%S")
|
|
163
|
+
iteration_text = f" EoF Iteration {self.__optimization_problem.GetStep()}"
|
|
164
|
+
iteration_output = f"{'#'} {iteration_text} [Time: {now_str}] {'#'}"
|
|
165
|
+
divided_line = len(iteration_output) * '#'
|
|
166
|
+
to_print = f"{divided_line}\n{iteration_output}\n{divided_line}\n"
|
|
167
|
+
Kratos.Logger.PrintInfo(to_print)
|
|
168
|
+
|
|
169
|
+
def UpdateMasterControlAndLogFields(self, new_control_field: numpy.ndarray) -> bool:
|
|
170
|
+
master_control_updated = False
|
|
171
|
+
master_control = self.GetMasterControl()
|
|
172
|
+
control_change_norm = numpy.linalg.norm(master_control.GetControlField().Evaluate().reshape(-1)-new_control_field)
|
|
173
|
+
if control_change_norm > 1e-15:
|
|
174
|
+
# first out put the fields and update step
|
|
175
|
+
CallOnAll(self.__optimization_problem.GetListOfProcesses("output_processes"), Kratos.OutputProcess.PrintOutput)
|
|
176
|
+
self.LogOptimizationStep()
|
|
177
|
+
self.__optimization_problem.AdvanceStep()
|
|
178
|
+
# convert numpy array to tensor adaptor
|
|
179
|
+
new_control_field_cta = master_control.GetEmptyField()
|
|
180
|
+
number_of_entities = []
|
|
181
|
+
shapes = []
|
|
182
|
+
for control in master_control.GetListOfControls():
|
|
183
|
+
number_of_entities.append(len(control.GetControlField().GetContainer()))
|
|
184
|
+
shapes.append(control.GetControlField().GetItemShape())
|
|
185
|
+
|
|
186
|
+
new_control_field_cta.data[:] = new_control_field
|
|
187
|
+
Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(new_control_field_cta, perform_store_data_recursively=False, copy=False).StoreData()
|
|
188
|
+
# now update the master control
|
|
189
|
+
master_control.Update(new_control_field_cta)
|
|
190
|
+
master_control_updated = True
|
|
191
|
+
return master_control_updated
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import KratosMultiphysics as Kratos
|
|
2
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
|
|
3
|
+
from KratosMultiphysics.OptimizationApplication.responses.response_routine import ResponseRoutine
|
|
4
|
+
from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl
|
|
5
|
+
from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
|
|
6
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import DictLogger
|
|
7
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import TimeLogger
|
|
8
|
+
from KratosMultiphysics.OptimizationApplication.utilities.response_utilities import EvaluateResponseExpression
|
|
9
|
+
from KratosMultiphysics.kratos_utilities import IssueDeprecationWarning
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
class StandardizedSciPyConstraint(ResponseRoutine):
|
|
13
|
+
"""Standardized SciPy constraint response function
|
|
14
|
+
|
|
15
|
+
This class creates instances to create constraint routine that SciPy is required to handle constraints.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, parameters: Kratos.Parameters, master_control: MasterControl, optimization_problem: OptimizationProblem, required_buffer_size: int = 2):
|
|
21
|
+
# backward compatibility
|
|
22
|
+
if parameters.Has("response_name"):
|
|
23
|
+
IssueDeprecationWarning(self.__class__.__name__, "\"response_name\" is deprecated. Please use \"response_expression\".")
|
|
24
|
+
parameters.AddString("response_expression", parameters["response_name"].GetString())
|
|
25
|
+
parameters.RemoveValue("response_name")
|
|
26
|
+
|
|
27
|
+
default_parameters = Kratos.Parameters("""{
|
|
28
|
+
"response_expression" : "",
|
|
29
|
+
"upper_boundary" : 1e16,
|
|
30
|
+
"lower_boundary" :-1e16
|
|
31
|
+
}""")
|
|
32
|
+
|
|
33
|
+
parameters.ValidateAndAssignDefaults(default_parameters)
|
|
34
|
+
|
|
35
|
+
response = EvaluateResponseExpression(parameters["response_expression"].GetString(), optimization_problem)
|
|
36
|
+
|
|
37
|
+
super().__init__(master_control, response)
|
|
38
|
+
|
|
39
|
+
if required_buffer_size < 2:
|
|
40
|
+
raise RuntimeError(f"Standardized objective requires 2 as minimum buffer size. [ response name = {self.GetResponseName()} ]")
|
|
41
|
+
|
|
42
|
+
component_data_view = ComponentDataView(response, optimization_problem)
|
|
43
|
+
component_data_view.SetDataBuffer(required_buffer_size)
|
|
44
|
+
|
|
45
|
+
self.__optimization_problem = optimization_problem
|
|
46
|
+
self.__buffered_data = component_data_view.GetBufferedData()
|
|
47
|
+
self.__unbuffered_data = component_data_view.GetUnBufferedData()
|
|
48
|
+
|
|
49
|
+
self.upper_bound = parameters["upper_boundary"].GetDouble()
|
|
50
|
+
self.lower_bound = parameters["lower_boundary"].GetDouble()
|
|
51
|
+
|
|
52
|
+
def CalculateStandardizedValue(self, x:np.array, save_data: bool = True) -> float:
|
|
53
|
+
control_field = self.GetMasterControl().GetEmptyField()
|
|
54
|
+
control_field.data[:] = x
|
|
55
|
+
Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(control_field, perform_store_data_recursively=False, copy=False).StoreData()
|
|
56
|
+
|
|
57
|
+
with TimeLogger(f"StandardizedObjective::Calculate {self.GetResponseName()} value", None, "Finished"):
|
|
58
|
+
response_value = self.CalculateValue(control_field)
|
|
59
|
+
standardized_response_value = response_value
|
|
60
|
+
|
|
61
|
+
if not self.__unbuffered_data.HasValue("initial_value"):
|
|
62
|
+
self.__unbuffered_data["initial_value"] = response_value
|
|
63
|
+
|
|
64
|
+
if save_data:
|
|
65
|
+
if self.__buffered_data.HasValue("value"): del self.__buffered_data["value"]
|
|
66
|
+
self.__buffered_data["value"] = response_value
|
|
67
|
+
|
|
68
|
+
DictLogger("Constraint info",self.GetInfo())
|
|
69
|
+
|
|
70
|
+
return standardized_response_value
|
|
71
|
+
|
|
72
|
+
def GetValue(self, step_index: int = 0) -> float:
|
|
73
|
+
return self.__buffered_data.GetValue("value", step_index)
|
|
74
|
+
|
|
75
|
+
def GetStandardizedValue(self, step_index: int = 0) -> float:
|
|
76
|
+
return self.GetValue(step_index)
|
|
77
|
+
|
|
78
|
+
def CalculateStandardizedGradient(self, x:np.array, save_field: bool = True) -> np.array:
|
|
79
|
+
|
|
80
|
+
self.CalculateStandardizedValue(x, False) # Compute new primal if x has changed. Does nothing if x the same.
|
|
81
|
+
|
|
82
|
+
with TimeLogger(f"StandardizedObjective::Calculate {self.GetResponseName()} gradients", None, "Finished"):
|
|
83
|
+
gradient_combined_tensor_adaptor = self.CalculateGradient()
|
|
84
|
+
if save_field:
|
|
85
|
+
# save the physical gradients for post processing in unbuffered data container.
|
|
86
|
+
for physical_var, physical_gradient in self.GetRequiredPhysicalGradients().items():
|
|
87
|
+
for physical_gradient_ta in physical_gradient.GetTensorAdaptors():
|
|
88
|
+
variable_name = f"d{self.GetResponseName()}_d{physical_var.Name()}"
|
|
89
|
+
if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name]
|
|
90
|
+
# cloning is a cheap operation, it only moves underlying pointers
|
|
91
|
+
# does not create additional memory.
|
|
92
|
+
self.__unbuffered_data[variable_name] = physical_gradient_ta.Clone()
|
|
93
|
+
|
|
94
|
+
# save the filtered gradients for post processing in unbuffered data container.
|
|
95
|
+
for gradient_ta, control in zip(gradient_combined_tensor_adaptor.GetTensorAdaptors(), self.GetMasterControl().GetListOfControls()):
|
|
96
|
+
variable_name = f"d{self.GetResponseName()}_d{control.GetName()}"
|
|
97
|
+
if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name]
|
|
98
|
+
# cloning is a cheap operation, it only moves underlying pointers
|
|
99
|
+
# does not create additional memory.
|
|
100
|
+
self.__unbuffered_data[variable_name] = gradient_ta.Clone()
|
|
101
|
+
|
|
102
|
+
return gradient_combined_tensor_adaptor.data.reshape(-1)
|
|
103
|
+
|
|
104
|
+
def GetValue(self, step_index: int = 0) -> float:
|
|
105
|
+
return self.__buffered_data.GetValue("value", step_index)
|
|
106
|
+
|
|
107
|
+
def GetStandardizedValue(self, step_index: int = 0) -> float:
|
|
108
|
+
return self.GetValue(step_index) - self.GetStandardizedReferenceValue()
|
|
109
|
+
|
|
110
|
+
def GetUpperBound(self):
|
|
111
|
+
return self.upper_bound
|
|
112
|
+
|
|
113
|
+
def GetLowerBound(self):
|
|
114
|
+
return self.lower_bound
|
|
115
|
+
|
|
116
|
+
def GetInfo(self) -> dict:
|
|
117
|
+
info = {
|
|
118
|
+
"name": self.GetResponseName(),
|
|
119
|
+
"value": self.GetValue(),
|
|
120
|
+
"upper_bound": self.upper_bound,
|
|
121
|
+
"lower_bound": self.lower_bound
|
|
122
|
+
}
|
|
123
|
+
return info
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import KratosMultiphysics as Kratos
|
|
2
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
|
|
3
|
+
from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl
|
|
4
|
+
from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
|
|
5
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import DictLogger
|
|
6
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import TimeLogger
|
|
7
|
+
from KratosMultiphysics.OptimizationApplication.utilities.response_utilities import EvaluateResponseExpression
|
|
8
|
+
from KratosMultiphysics.kratos_utilities import IssueDeprecationWarning
|
|
9
|
+
from KratosMultiphysics.OptimizationApplication.responses.response_routine import ResponseRoutine
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
class StandardizedSciPyObjective(ResponseRoutine):
|
|
14
|
+
"""Standardized SciPy objective response routine.
|
|
15
|
+
|
|
16
|
+
This class transformed a user-given optimization problem into the standard format.
|
|
17
|
+
Supported objective types:
|
|
18
|
+
"minimization",
|
|
19
|
+
"maximization"
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, parameters: Kratos.Parameters, master_control: MasterControl, optimization_problem: OptimizationProblem, required_buffer_size: int = 2):
|
|
24
|
+
# backward compatibility
|
|
25
|
+
if parameters.Has("response_name"):
|
|
26
|
+
IssueDeprecationWarning(self.__class__.__name__, "\"response_name\" is deprecated. Please use \"response_expression\".")
|
|
27
|
+
parameters.AddString("response_expression", parameters["response_name"].GetString())
|
|
28
|
+
parameters.RemoveValue("response_name")
|
|
29
|
+
|
|
30
|
+
default_parameters = Kratos.Parameters("""{
|
|
31
|
+
"response_expression": "",
|
|
32
|
+
"type" : "",
|
|
33
|
+
"scaling" : 1.0
|
|
34
|
+
}""")
|
|
35
|
+
parameters.ValidateAndAssignDefaults(default_parameters)
|
|
36
|
+
|
|
37
|
+
response = EvaluateResponseExpression(parameters["response_expression"].GetString(), optimization_problem)
|
|
38
|
+
|
|
39
|
+
super().__init__(master_control, response)
|
|
40
|
+
|
|
41
|
+
if required_buffer_size < 2:
|
|
42
|
+
raise RuntimeError(f"Standardized objective requires 2 as minimum buffer size. [ response name = {self.GetResponseName()} ]")
|
|
43
|
+
|
|
44
|
+
component_data_view = ComponentDataView(response, optimization_problem)
|
|
45
|
+
component_data_view.SetDataBuffer(required_buffer_size)
|
|
46
|
+
|
|
47
|
+
self.__optimization_problem = optimization_problem
|
|
48
|
+
self.__buffered_data = component_data_view.GetBufferedData()
|
|
49
|
+
self.__unbuffered_data = component_data_view.GetUnBufferedData()
|
|
50
|
+
|
|
51
|
+
self.computed = False
|
|
52
|
+
|
|
53
|
+
scaling = parameters["scaling"].GetDouble()
|
|
54
|
+
if scaling < 0.0:
|
|
55
|
+
raise RuntimeError(f"Scaling should be always positive [ given scale = {scaling}]")
|
|
56
|
+
|
|
57
|
+
self.__objective_type = parameters["type"].GetString()
|
|
58
|
+
if self.__objective_type == "minimization":
|
|
59
|
+
self.__scaling = scaling
|
|
60
|
+
elif self.__objective_type == "maximization":
|
|
61
|
+
self.__scaling = -scaling
|
|
62
|
+
else:
|
|
63
|
+
raise RuntimeError(f"Requesting unsupported type {self.__objective_type} for objective response function. Supported types are: \n\tminimization\n\tmaximization")
|
|
64
|
+
|
|
65
|
+
def GetInitialValue(self) -> float:
|
|
66
|
+
if self.__unbuffered_data.HasValue("initial_value"):
|
|
67
|
+
return self.__unbuffered_data["initial_value"] * self.__scaling
|
|
68
|
+
else:
|
|
69
|
+
raise RuntimeError(f"Response value for {self.GetResponseName()} is not calculated yet.")
|
|
70
|
+
|
|
71
|
+
def CalculateStandardizedValue(self, x:np.array, save_data: bool = True) -> float:
|
|
72
|
+
|
|
73
|
+
control_field = self.GetMasterControl().GetEmptyField()
|
|
74
|
+
control_field.data[:] = x
|
|
75
|
+
Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(control_field, perform_store_data_recursively=False, copy=False).StoreData()
|
|
76
|
+
|
|
77
|
+
with TimeLogger(f"StandardizedObjective::Calculate {self.GetResponseName()} value", None, "Finished"):
|
|
78
|
+
response_value = self.CalculateValue(control_field)
|
|
79
|
+
standardized_response_value = response_value * self.__scaling
|
|
80
|
+
|
|
81
|
+
if not self.__unbuffered_data.HasValue("initial_value"):
|
|
82
|
+
self.__unbuffered_data["initial_value"] = response_value
|
|
83
|
+
|
|
84
|
+
if save_data:
|
|
85
|
+
|
|
86
|
+
if self.__buffered_data.HasValue("value"): del self.__buffered_data["value"]
|
|
87
|
+
self.__buffered_data["value"] = response_value
|
|
88
|
+
self.computed = True
|
|
89
|
+
|
|
90
|
+
DictLogger("Objective info",self.GetInfo())
|
|
91
|
+
|
|
92
|
+
return standardized_response_value
|
|
93
|
+
|
|
94
|
+
def GetValue(self, step_index: int = 0) -> float:
|
|
95
|
+
return self.__buffered_data.GetValue("value", step_index)
|
|
96
|
+
|
|
97
|
+
def GetStandardizedValue(self, step_index: int = 0) -> float:
|
|
98
|
+
return self.GetValue(step_index) * self.__scaling
|
|
99
|
+
|
|
100
|
+
def CalculateStandardizedGradient(self, x:np.array, save_field: bool = True) -> np.array:
|
|
101
|
+
|
|
102
|
+
self.CalculateStandardizedValue(x, False) # Compute new primal if x has changed. Does nothing if x the same
|
|
103
|
+
|
|
104
|
+
with TimeLogger(f"StandardizedObjective::Calculate {self.GetResponseName()} gradients", None, "Finished"):
|
|
105
|
+
gradient_combined_tensor_adaptor = self.CalculateGradient()
|
|
106
|
+
if save_field:
|
|
107
|
+
# save the physical gradients for post processing in unbuffered data container.
|
|
108
|
+
for physical_var, physical_gradient in self.GetRequiredPhysicalGradients().items():
|
|
109
|
+
for physical_gradient_ta in physical_gradient.GetTensorAdaptors():
|
|
110
|
+
variable_name = f"d{self.GetResponseName()}_d{physical_var.Name()}"
|
|
111
|
+
if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name]
|
|
112
|
+
# cloning is a cheap operation, it only moves underlying pointers
|
|
113
|
+
# does not create additional memory.
|
|
114
|
+
self.__unbuffered_data[variable_name] = physical_gradient_ta.Clone()
|
|
115
|
+
|
|
116
|
+
# save the filtered gradients for post processing in unbuffered data container.
|
|
117
|
+
for gradient_ta, control in zip(gradient_combined_tensor_adaptor.GetTensorAdaptors(), self.GetMasterControl().GetListOfControls()):
|
|
118
|
+
variable_name = f"d{self.GetResponseName()}_d{control.GetName()}"
|
|
119
|
+
if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name]
|
|
120
|
+
# cloning is a cheap operation, it only moves underlying pointers
|
|
121
|
+
# does not create additional memory.
|
|
122
|
+
self.__unbuffered_data[variable_name] = gradient_ta.Clone()
|
|
123
|
+
|
|
124
|
+
return gradient_combined_tensor_adaptor.data.reshape(-1) * self.__scaling
|
|
125
|
+
|
|
126
|
+
def GetRelativeChange(self) -> float:
|
|
127
|
+
if self.__optimization_problem.GetStep() > 0:
|
|
128
|
+
return self.GetStandardizedValue() / self.GetStandardizedValue(1) - 1.0 if abs(self.GetStandardizedValue(1)) > 1e-12 else self.GetStandardizedValue()
|
|
129
|
+
else:
|
|
130
|
+
return 0.0
|
|
131
|
+
|
|
132
|
+
def GetAbsoluteChange(self) -> float:
|
|
133
|
+
return self.GetValue() - self.GetInitialValue()
|
|
134
|
+
|
|
135
|
+
def GetInfo(self) -> dict:
|
|
136
|
+
info = {
|
|
137
|
+
"name": self.GetResponseName(),
|
|
138
|
+
"type": self.__objective_type,
|
|
139
|
+
"value": self.GetValue(),
|
|
140
|
+
"std_value": self.GetStandardizedValue(),
|
|
141
|
+
"abs_change": self.GetAbsoluteChange(),
|
|
142
|
+
"rel_change [%]": self.GetRelativeChange() * 100.0
|
|
143
|
+
}
|
|
144
|
+
init_value = self.GetInitialValue()
|
|
145
|
+
if init_value:
|
|
146
|
+
info["abs_change [%]"] = self.GetAbsoluteChange()/init_value * 100
|
|
147
|
+
|
|
148
|
+
return info
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import KratosMultiphysics as Kratos
|
|
2
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
|
|
3
|
+
from KratosMultiphysics.OptimizationApplication.responses.response_routine import ResponseRoutine
|
|
4
|
+
from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl
|
|
5
|
+
from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
|
|
6
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import DictLogger
|
|
7
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import TimeLogger
|
|
8
|
+
from KratosMultiphysics.OptimizationApplication.utilities.response_utilities import EvaluateResponseExpression
|
|
9
|
+
from KratosMultiphysics.kratos_utilities import IssueDeprecationWarning
|
|
10
|
+
|
|
11
|
+
class StandardizedConstraint(ResponseRoutine):
|
|
12
|
+
"""Standardized constraint response function
|
|
13
|
+
|
|
14
|
+
This class creates instances to standardize any response function for the specified type of the constraint.
|
|
15
|
+
Supported constraint types:
|
|
16
|
+
"=",
|
|
17
|
+
"<",
|
|
18
|
+
"<=,
|
|
19
|
+
">",
|
|
20
|
+
">="
|
|
21
|
+
|
|
22
|
+
The reference value for the constraint either can be the "initial_value" or a specified value.
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
def __init__(self, parameters: Kratos.Parameters, master_control: MasterControl, optimization_problem: OptimizationProblem, required_buffer_size: int = 2):
|
|
26
|
+
# backward compatibility
|
|
27
|
+
if parameters.Has("response_name"):
|
|
28
|
+
IssueDeprecationWarning(self.__class__.__name__, "\"response_name\" is deprecated. Please use \"response_expression\".")
|
|
29
|
+
parameters.AddString("response_expression", parameters["response_name"].GetString())
|
|
30
|
+
parameters.RemoveValue("response_name")
|
|
31
|
+
|
|
32
|
+
default_parameters = Kratos.Parameters("""{
|
|
33
|
+
"response_expression" : "",
|
|
34
|
+
"type" : "",
|
|
35
|
+
"scaling" : 1.0,
|
|
36
|
+
"violation_scaling" : 1.0,
|
|
37
|
+
"scaled_ref_value" : "initial_value"
|
|
38
|
+
}""")
|
|
39
|
+
|
|
40
|
+
if parameters.Has("scaled_ref_value") and parameters["scaled_ref_value"].IsDouble():
|
|
41
|
+
default_parameters["scaled_ref_value"].SetDouble(0.0)
|
|
42
|
+
|
|
43
|
+
parameters.ValidateAndAssignDefaults(default_parameters)
|
|
44
|
+
|
|
45
|
+
response = EvaluateResponseExpression(parameters["response_expression"].GetString(), optimization_problem)
|
|
46
|
+
|
|
47
|
+
super().__init__(master_control, response)
|
|
48
|
+
|
|
49
|
+
if required_buffer_size < 2:
|
|
50
|
+
raise RuntimeError(f"Standardized objective requires 2 as minimum buffer size. [ response name = {self.GetResponseName()} ]")
|
|
51
|
+
|
|
52
|
+
component_data_view = ComponentDataView(response, optimization_problem)
|
|
53
|
+
component_data_view.SetDataBuffer(required_buffer_size)
|
|
54
|
+
|
|
55
|
+
self.__optimization_problem = optimization_problem
|
|
56
|
+
self.__buffered_data = component_data_view.GetBufferedData()
|
|
57
|
+
self.__unbuffered_data = component_data_view.GetUnBufferedData()
|
|
58
|
+
|
|
59
|
+
scaling = parameters["scaling"].GetDouble()
|
|
60
|
+
if scaling < 0.0:
|
|
61
|
+
raise RuntimeError(f"Scaling should be always positive [ given scale = {scaling}]")
|
|
62
|
+
|
|
63
|
+
if parameters["scaled_ref_value"].IsDouble():
|
|
64
|
+
self.__ref_type = "specified_value"
|
|
65
|
+
self.__reference_value = parameters["scaled_ref_value"].GetDouble()
|
|
66
|
+
elif parameters["scaled_ref_value"].IsString() and parameters["scaled_ref_value"].GetString() == "initial_value":
|
|
67
|
+
self.__ref_type = "initial_value"
|
|
68
|
+
self.__reference_value = None
|
|
69
|
+
else:
|
|
70
|
+
raise RuntimeError(f"Provided \"reference_type\" = {self.__ref_type} is not supported for constraint response functions. Followings are supported options: \n\tinitial_value\n\tfloat value")
|
|
71
|
+
|
|
72
|
+
self.__violation_scaling = parameters["violation_scaling"].GetDouble()
|
|
73
|
+
self.__constraint_type = parameters["type"].GetString()
|
|
74
|
+
if self.__constraint_type in ["<=", "="]:
|
|
75
|
+
self.__scaling = scaling
|
|
76
|
+
elif self.__constraint_type in [">="]:
|
|
77
|
+
self.__scaling = -scaling
|
|
78
|
+
if not self.__reference_value is None: self.__reference_value *= -1
|
|
79
|
+
else:
|
|
80
|
+
raise RuntimeError(f"Provided \"type\" = {self.__constraint_type} is not supported in constraint response functions. Followings are supported options: \n\t=\n\t<=\n\t<\n\t>=\n\t>")
|
|
81
|
+
|
|
82
|
+
def IsEqualityType(self) -> str:
|
|
83
|
+
return self.__constraint_type == "="
|
|
84
|
+
|
|
85
|
+
def GetStandardizedReferenceValue(self) -> float:
|
|
86
|
+
if self.__reference_value is not None:
|
|
87
|
+
return self.__reference_value
|
|
88
|
+
else:
|
|
89
|
+
if self.__unbuffered_data.HasValue("initial_value"):
|
|
90
|
+
return self.__unbuffered_data["initial_value"] * self.__scaling
|
|
91
|
+
else:
|
|
92
|
+
raise RuntimeError(f"Response value for {self.GetResponseName()} is not calculated yet.")
|
|
93
|
+
|
|
94
|
+
def CalculateStandardizedValue(self, control_field: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor, save_value: bool = True) -> float:
|
|
95
|
+
with TimeLogger(f"StandardizedConstraint::Calculate {self.GetResponseName()} value", None, "Finished"):
|
|
96
|
+
response_value = self.CalculateValue(control_field)
|
|
97
|
+
standardized_response_value = response_value * self.__scaling
|
|
98
|
+
|
|
99
|
+
if not self.__unbuffered_data.HasValue("initial_value"):
|
|
100
|
+
self.__unbuffered_data["initial_value"] = response_value
|
|
101
|
+
|
|
102
|
+
standardized_response_value -= self.GetStandardizedReferenceValue()
|
|
103
|
+
|
|
104
|
+
if save_value:
|
|
105
|
+
if self.__buffered_data.HasValue("value"): del self.__buffered_data["value"]
|
|
106
|
+
if self.__buffered_data.HasValue("std_value"): del self.__buffered_data["std_value"]
|
|
107
|
+
self.__buffered_data["value"] = response_value
|
|
108
|
+
self.__buffered_data["std_value"] = standardized_response_value
|
|
109
|
+
|
|
110
|
+
DictLogger("Constraint info",self.GetInfo())
|
|
111
|
+
|
|
112
|
+
return standardized_response_value
|
|
113
|
+
|
|
114
|
+
def IsActive(self):
|
|
115
|
+
return self.GetStandardizedValue() > 0.0
|
|
116
|
+
|
|
117
|
+
def CalculateStandardizedGradient(self, save_field: bool = True) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor:
|
|
118
|
+
|
|
119
|
+
with TimeLogger(f"StandardizedConstraint::Calculate {self.GetResponseName()} gradients", None, "Finished"):
|
|
120
|
+
gradient_cta = self.CalculateGradient()
|
|
121
|
+
if save_field:
|
|
122
|
+
# save the physical gradients for post processing in unbuffered data container.
|
|
123
|
+
for physical_var, physical_gradient in self.GetRequiredPhysicalGradients().items():
|
|
124
|
+
variable_name = f"d{self.GetResponseName()}_d{physical_var.Name()}"
|
|
125
|
+
if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name]
|
|
126
|
+
# cloning is a cheap operation, it only moves underlying pointers
|
|
127
|
+
# does not create additional memory.
|
|
128
|
+
self.__unbuffered_data[variable_name] = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(physical_gradient)
|
|
129
|
+
|
|
130
|
+
# save the filtered gradients for post processing in unbuffered data container.
|
|
131
|
+
for gradient_ta, control in zip(gradient_cta.GetTensorAdaptors(), self.GetMasterControl().GetListOfControls()):
|
|
132
|
+
variable_name = f"d{self.GetResponseName()}_d{control.GetName()}"
|
|
133
|
+
if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name]
|
|
134
|
+
# cloning is a cheap operation, it only moves underlying pointers
|
|
135
|
+
# does not create additional memory.
|
|
136
|
+
self.__unbuffered_data[variable_name] = Kratos.TensorAdaptors.DoubleTensorAdaptor(gradient_ta)
|
|
137
|
+
|
|
138
|
+
gradient_cta.data[:] *= self.__scaling
|
|
139
|
+
Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(gradient_cta, perform_store_data_recursively=False, copy=False).StoreData()
|
|
140
|
+
return gradient_cta
|
|
141
|
+
|
|
142
|
+
def GetValue(self, step_index: int = 0) -> float:
|
|
143
|
+
return self.__buffered_data.GetValue("value", step_index)
|
|
144
|
+
|
|
145
|
+
def GetStandardizedValue(self, step_index: int = 0) -> float:
|
|
146
|
+
return self.GetValue(step_index) * self.__scaling - self.GetStandardizedReferenceValue()
|
|
147
|
+
|
|
148
|
+
def GetScaledViolationValue(self, step_index: int = 0) -> float:
|
|
149
|
+
value = self.GetStandardizedValue(step_index)
|
|
150
|
+
return max(0.0, value * self.__violation_scaling)
|
|
151
|
+
|
|
152
|
+
def GetAbsoluteViolation(self, step_index: int = 0) -> float:
|
|
153
|
+
is_violated = self.IsEqualityType() or self.GetStandardizedValue(step_index) >= 0.0
|
|
154
|
+
return self.GetStandardizedValue(step_index) * is_violated
|
|
155
|
+
|
|
156
|
+
def GetRelativeViolation(self, step_index: int = 0) -> float:
|
|
157
|
+
return self.GetAbsoluteViolation(step_index) / self.GetStandardizedReferenceValue() if abs(self.GetStandardizedReferenceValue()) > 1e-12 else self.GetAbsoluteViolation(step_index)
|
|
158
|
+
|
|
159
|
+
def GetRelativeChange(self) -> float:
|
|
160
|
+
if self.__optimization_problem.GetStep() > 1:
|
|
161
|
+
return self.GetStandardizedValue() / self.GetStandardizedValue(1) - 1.0 if abs(self.GetStandardizedValue(1)) > 1e-12 else self.GetStandardizedValue()
|
|
162
|
+
else:
|
|
163
|
+
return 0.0
|
|
164
|
+
|
|
165
|
+
def GetAbsoluteChange(self) -> float:
|
|
166
|
+
return self.GetStandardizedValue() / self.GetStandardizedReferenceValue() - 1.0 if abs(self.GetStandardizedReferenceValue()) > 1e-12 else self.GetStandardizedValue()
|
|
167
|
+
|
|
168
|
+
def GetInfo(self) -> dict:
|
|
169
|
+
info = {
|
|
170
|
+
"name": self.GetResponseName(),
|
|
171
|
+
"value": self.GetValue(),
|
|
172
|
+
"scaled_value": self.GetValue() * abs(self.__scaling),
|
|
173
|
+
"type": self.__constraint_type,
|
|
174
|
+
"ref_value": self.GetStandardizedReferenceValue(),
|
|
175
|
+
"abs_change": self.GetAbsoluteChange(),
|
|
176
|
+
"rel_change [%]": self.GetRelativeChange() * 100.0,
|
|
177
|
+
"abs_violation [%]": self.GetAbsoluteViolation() * 100,
|
|
178
|
+
"rel_violation [%]": self.GetRelativeViolation() * 100.0
|
|
179
|
+
}
|
|
180
|
+
return info
|