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,222 @@
|
|
|
1
|
+
# | / |
|
|
2
|
+
# ' / __| _` | __| _ \ __|
|
|
3
|
+
# . \ | ( | | ( |\__ `
|
|
4
|
+
# _|\_\_| \__,_|\__|\___/ ____/
|
|
5
|
+
# Multi-Physics
|
|
6
|
+
#
|
|
7
|
+
# License: BSD License
|
|
8
|
+
# license: OptimizationApplication/license.txt
|
|
9
|
+
#
|
|
10
|
+
# Main authors: Suneth Warnakulasuriya
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
import time as timer
|
|
14
|
+
import datetime
|
|
15
|
+
import KratosMultiphysics as Kratos
|
|
16
|
+
from functools import wraps
|
|
17
|
+
import typing
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def AddFileLoggerOutput(logger_file_name):
|
|
21
|
+
logger_file = Kratos.FileLoggerOutput(logger_file_name)
|
|
22
|
+
default_severity = Kratos.Logger.GetDefaultOutput().GetSeverity()
|
|
23
|
+
Kratos.Logger.GetDefaultOutput().SetSeverity(Kratos.Logger.Severity.WARNING)
|
|
24
|
+
Kratos.Logger.AddOutput(logger_file)
|
|
25
|
+
|
|
26
|
+
return default_severity, logger_file
|
|
27
|
+
|
|
28
|
+
def RemoveFileLoggerOutput(default_severity, logger_file):
|
|
29
|
+
Kratos.Logger.Flush()
|
|
30
|
+
Kratos.Logger.RemoveOutput(logger_file)
|
|
31
|
+
Kratos.Logger.GetDefaultOutput().SetSeverity(default_severity)
|
|
32
|
+
|
|
33
|
+
class FileLogger:
|
|
34
|
+
"""@brief A context responsible for managing the lifetime of logger files."""
|
|
35
|
+
def __init__(self, logger_file_name: str):
|
|
36
|
+
self.__logger_file_name = logger_file_name
|
|
37
|
+
|
|
38
|
+
def __enter__(self):
|
|
39
|
+
self.__default_severity, self.__logger_file = AddFileLoggerOutput(self.__logger_file_name)
|
|
40
|
+
|
|
41
|
+
def __exit__(self, exit_type, exit_value, exit_traceback):
|
|
42
|
+
RemoveFileLoggerOutput(self.__default_severity, self.__logger_file)
|
|
43
|
+
|
|
44
|
+
class TimeLogger:
|
|
45
|
+
"""@brief A context responsible for outputting execution times."""
|
|
46
|
+
def __init__(self, topic: str, entry_msg: str , exit_msg: str, end_new_line: bool=True):
|
|
47
|
+
self.topic = topic
|
|
48
|
+
self.entry_msg = entry_msg
|
|
49
|
+
self.exit_msg = exit_msg
|
|
50
|
+
self.start_time = None
|
|
51
|
+
self.end_new_line = end_new_line
|
|
52
|
+
|
|
53
|
+
def __enter__(self):
|
|
54
|
+
if self.entry_msg is not None:
|
|
55
|
+
Kratos.Logger.PrintInfo(self.topic, self.entry_msg)
|
|
56
|
+
self.start_time = timer.time()
|
|
57
|
+
|
|
58
|
+
def __exit__(self, exit_type, exit_value, exit_traceback):
|
|
59
|
+
if self.exit_msg is not None:
|
|
60
|
+
elapsed_time = timer.time() - self.start_time
|
|
61
|
+
if self.end_new_line:
|
|
62
|
+
Kratos.Logger.PrintInfo(self.topic, "{:s} - [ Elapsed time: {:s} ]".format(self.exit_msg, str(datetime.timedelta(seconds=round(elapsed_time))))+"\n")
|
|
63
|
+
else:
|
|
64
|
+
Kratos.Logger.PrintInfo(self.topic, "{:s} - [ Elapsed time: {:s} ]".format(self.exit_msg, str(datetime.timedelta(seconds=round(elapsed_time)))))
|
|
65
|
+
|
|
66
|
+
class OptimizationAlgorithmTimeLogger:
|
|
67
|
+
"""@brief A context responsible for outputting execution times."""
|
|
68
|
+
def __init__(self, optimizer_name: str, optimization_itr: int):
|
|
69
|
+
self.start_time = None
|
|
70
|
+
self.optimization_itr = optimization_itr
|
|
71
|
+
self.optimizer_name = optimizer_name
|
|
72
|
+
|
|
73
|
+
def __enter__(self):
|
|
74
|
+
self.start_time = timer.time()
|
|
75
|
+
|
|
76
|
+
def __exit__(self, exit_type, exit_value, exit_traceback):
|
|
77
|
+
|
|
78
|
+
current_time = timer.time()
|
|
79
|
+
elapsed_time = current_time - self.start_time
|
|
80
|
+
elapsed_time_string = str(datetime.timedelta(seconds=round(elapsed_time)))
|
|
81
|
+
|
|
82
|
+
iteration_text = f"{self.optimizer_name} EoF Iteration {self.optimization_itr}"
|
|
83
|
+
iteration_output = f"{'#'} {iteration_text} [Elapsed Time: {elapsed_time_string}] {'#'}"
|
|
84
|
+
|
|
85
|
+
divided_line = len(iteration_output) * '#'
|
|
86
|
+
|
|
87
|
+
to_print = f"{divided_line}\n{iteration_output}\n{divided_line}\n"
|
|
88
|
+
|
|
89
|
+
Kratos.Logger.PrintInfo(to_print)
|
|
90
|
+
|
|
91
|
+
class OptimizationAnalysisTimeLogger:
|
|
92
|
+
|
|
93
|
+
def __enter__(self):
|
|
94
|
+
start_text = "Optimization Start"
|
|
95
|
+
|
|
96
|
+
self.start_time = datetime.datetime.now()
|
|
97
|
+
start_time_string = self.start_time.strftime("%Y-%m-%d %H:%M:%S")
|
|
98
|
+
|
|
99
|
+
time_string = f"** {start_time_string} **"
|
|
100
|
+
separator_string = len(time_string) * '*'
|
|
101
|
+
center_string = f"**{start_text.center(len(str(time_string))-4)}**"
|
|
102
|
+
final_string = f"{separator_string}\n{center_string}\n{time_string}\n{separator_string}"
|
|
103
|
+
|
|
104
|
+
Kratos.Logger.PrintInfo(final_string)
|
|
105
|
+
|
|
106
|
+
def __exit__(self, exit_type, exit_value, exit_traceback):
|
|
107
|
+
|
|
108
|
+
end_text = "Optimization End"
|
|
109
|
+
|
|
110
|
+
end_time = datetime.datetime.now()
|
|
111
|
+
end_time_string = end_time.strftime("%Y-%m-%d %H:%M:%S")
|
|
112
|
+
|
|
113
|
+
elapsed_time = end_time - self.start_time
|
|
114
|
+
elapsed_time_string = str(datetime.timedelta(seconds=round(elapsed_time.total_seconds())))
|
|
115
|
+
|
|
116
|
+
time_string = f"** {end_time_string} [Elapsed Time: {elapsed_time_string}] **"
|
|
117
|
+
separator_string = len(time_string) * '*'
|
|
118
|
+
center_string = f"**{end_text.center(len(str(time_string))-4)}**"
|
|
119
|
+
final_string = f"{separator_string}\n{center_string}\n{time_string}\n{separator_string}"
|
|
120
|
+
|
|
121
|
+
Kratos.Logger.PrintInfo(final_string)
|
|
122
|
+
|
|
123
|
+
def DictLogger(title: str, data: dict):
|
|
124
|
+
|
|
125
|
+
# First do the formatting and converting to strings
|
|
126
|
+
for key, value in data.items():
|
|
127
|
+
if isinstance(value, (float, int)):
|
|
128
|
+
if abs(value) >= 1e6 or abs(value) < 1e-6:
|
|
129
|
+
data[key] = "{:.6e}".format(value)
|
|
130
|
+
else:
|
|
131
|
+
data[key] = "{:.6f}".format(value)
|
|
132
|
+
|
|
133
|
+
# Determine the maximum length of labels
|
|
134
|
+
max_label_len = max(len(str(label)) for label in data.keys())
|
|
135
|
+
max_value_len = max(len(str(value)) for value in data.values())
|
|
136
|
+
|
|
137
|
+
title_len = len(str(title)) + 8
|
|
138
|
+
|
|
139
|
+
# Calculate the row width
|
|
140
|
+
if title_len > max_label_len + max_value_len + 7:
|
|
141
|
+
row_width = title_len
|
|
142
|
+
max_value_len = row_width - max_label_len - 7
|
|
143
|
+
else:
|
|
144
|
+
row_width = max_label_len + max_value_len + 7
|
|
145
|
+
|
|
146
|
+
# Create format strings for the labels and values
|
|
147
|
+
label_format = f"| {{:<{max_label_len}}} |"
|
|
148
|
+
|
|
149
|
+
# Build the table
|
|
150
|
+
table = '-' * row_width + "\n"
|
|
151
|
+
table += f"|{str(title).center(row_width - 2)}|\n"
|
|
152
|
+
table += '-' * row_width + "\n"
|
|
153
|
+
|
|
154
|
+
# Add the data to the table
|
|
155
|
+
for label, value in data.items():
|
|
156
|
+
table += f"{label_format.format(label)} {value:>{max_value_len}} |\n"
|
|
157
|
+
|
|
158
|
+
table += '-' * row_width
|
|
159
|
+
|
|
160
|
+
# now print
|
|
161
|
+
Kratos.Logger.PrintInfo(table)
|
|
162
|
+
|
|
163
|
+
def ListLogger(title: str, data: 'list[tuple[str, typing.Union[int, float, str]]]'):
|
|
164
|
+
# First do the formatting and converting to strings
|
|
165
|
+
sting_data: 'list[tuple[str, typing.Union[int, float, str]]]' = []
|
|
166
|
+
for key, value in data:
|
|
167
|
+
if isinstance(value, (float, int)):
|
|
168
|
+
if abs(value) >= 1e6 or abs(value) < 1e-6:
|
|
169
|
+
sting_data.append((key, "{:.6e}".format(value)))
|
|
170
|
+
else:
|
|
171
|
+
sting_data.append((key, "{:.6f}".format(value)))
|
|
172
|
+
|
|
173
|
+
# Determine the maximum length of labels
|
|
174
|
+
max_label_len = max(len(str(label)) for label, _ in data)
|
|
175
|
+
max_value_len = max(len(str(value)) for _, value in data)
|
|
176
|
+
|
|
177
|
+
title_len = len(str(title)) + 8
|
|
178
|
+
|
|
179
|
+
# Calculate the row width
|
|
180
|
+
if title_len > max_label_len + max_value_len + 7:
|
|
181
|
+
row_width = title_len
|
|
182
|
+
max_value_len = row_width - max_label_len - 7
|
|
183
|
+
else:
|
|
184
|
+
row_width = max_label_len + max_value_len + 7
|
|
185
|
+
|
|
186
|
+
# Create format strings for the labels and values
|
|
187
|
+
label_format = f"| {{:<{max_label_len}}} |"
|
|
188
|
+
|
|
189
|
+
# Build the table
|
|
190
|
+
table = '-' * row_width + "\n"
|
|
191
|
+
table += f"|{str(title).center(row_width - 2)}|\n"
|
|
192
|
+
table += '-' * row_width + "\n"
|
|
193
|
+
|
|
194
|
+
# Add the data to the table
|
|
195
|
+
for label, value in data:
|
|
196
|
+
table += f"{label_format.format(label)} {value:>{max_value_len}} |\n"
|
|
197
|
+
|
|
198
|
+
table += '-' * row_width
|
|
199
|
+
|
|
200
|
+
# now print
|
|
201
|
+
Kratos.Logger.PrintInfo(table)
|
|
202
|
+
|
|
203
|
+
def time_decorator(arg1=None, arg2=None, methodName=None):
|
|
204
|
+
def inner_func(func):
|
|
205
|
+
@wraps(func)
|
|
206
|
+
def wrapper(self,*args, **kwargs):
|
|
207
|
+
start_time = timer.perf_counter()
|
|
208
|
+
if arg1:
|
|
209
|
+
Kratos.Logger.Print(f"{func.__qualname__.split('.')[0]}::{func.__name__}: {arg1}")
|
|
210
|
+
result = func(self,*args, **kwargs)
|
|
211
|
+
end_time = timer.perf_counter()
|
|
212
|
+
elapsed_time = end_time - start_time
|
|
213
|
+
if arg2:
|
|
214
|
+
Kratos.Logger.Print(f"{func.__qualname__.split('.')[0]}::{func.__name__}: {arg2} - [ Elapsed time: {datetime.timedelta(seconds=round(elapsed_time))}] \n")
|
|
215
|
+
elif methodName:
|
|
216
|
+
method_to_call = getattr(self, methodName)
|
|
217
|
+
Kratos.Logger.Print(f"{func.__qualname__.split('.')[0]}::{func.__name__}: {method_to_call()} finished - [ Elapsed time: {datetime.timedelta(seconds=round(elapsed_time))}] \n")
|
|
218
|
+
else:
|
|
219
|
+
Kratos.Logger.Print(f"{func.__qualname__.split('.')[0]}::{func.__name__}: Finished - [ Elapsed time: {datetime.timedelta(seconds=round(elapsed_time))}] \n")
|
|
220
|
+
return result
|
|
221
|
+
return wrapper
|
|
222
|
+
return inner_func
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from enum import Enum
|
|
3
|
+
import KratosMultiphysics as Kratos
|
|
4
|
+
import KratosMultiphysics.OptimizationApplication as KratosOA
|
|
5
|
+
|
|
6
|
+
class ModelPartOperation:
|
|
7
|
+
class OperationType(Enum):
|
|
8
|
+
UNION = 1,
|
|
9
|
+
INTERSECT = 2
|
|
10
|
+
|
|
11
|
+
def __init__(self, model: Kratos.Model, operation_type: OperationType, suggested_model_part_name: str, list_of_operation_model_part_full_names: 'list[str]', add_neighbours: bool) -> None:
|
|
12
|
+
self.model = model
|
|
13
|
+
self.operation_type = operation_type
|
|
14
|
+
self.suggested_model_part_name = suggested_model_part_name
|
|
15
|
+
self.list_of_operation_model_part_full_names = sorted(list(set(list_of_operation_model_part_full_names)))
|
|
16
|
+
self.add_neighbours = add_neighbours
|
|
17
|
+
|
|
18
|
+
if len(list_of_operation_model_part_full_names) == 0:
|
|
19
|
+
raise RuntimeError("No operating model part names are provided.")
|
|
20
|
+
|
|
21
|
+
if suggested_model_part_name.find("#") != -1 or any([mp_name.find("#") != -1 for mp_name in list_of_operation_model_part_full_names]):
|
|
22
|
+
# find '#' in the model part names which is not allowed.
|
|
23
|
+
raise RuntimeError(f"The model part names cannot contain '#' character. Parsed model part names are as followings:\n\t suggested model part name: \"{suggested_model_part_name}\"\n\toperation model part names:\n\t" + "\n\t\t".join(list_of_operation_model_part_full_names))
|
|
24
|
+
|
|
25
|
+
# set the root model part. This needs to always exist.
|
|
26
|
+
self.root_model_part = self.model[self.list_of_operation_model_part_full_names[0].split(".")[0]]
|
|
27
|
+
self.status_msg = ""
|
|
28
|
+
|
|
29
|
+
def GetRootModelPart(self) -> Kratos.ModelPart:
|
|
30
|
+
return self.root_model_part
|
|
31
|
+
|
|
32
|
+
def GetModelPartFullName(self) -> str:
|
|
33
|
+
# check whether is there a need to perform binary operations
|
|
34
|
+
if self.operation_type == ModelPartOperation.OperationType.UNION or self.operation_type == ModelPartOperation.OperationType.INTERSECT:
|
|
35
|
+
if len(self.list_of_operation_model_part_full_names) == 1:
|
|
36
|
+
# all the operation model parts are the same, hence no need of doing an operation.
|
|
37
|
+
self.status_msg = ""
|
|
38
|
+
return self.list_of_operation_model_part_full_names[0]
|
|
39
|
+
|
|
40
|
+
# now check in the status messages of the root model part whether this operation is already added.
|
|
41
|
+
status_msg_prefix = "ModelPartUtilities_created#"
|
|
42
|
+
status_msg_suffix = f"#{self.operation_type.name}#{self.add_neighbours:d}#" + "#".join(self.list_of_operation_model_part_full_names)
|
|
43
|
+
status_msg_log = KratosOA.OptAppModelPartUtils.GetModelPartStatusLog(self.GetRootModelPart())
|
|
44
|
+
for status_msg in status_msg_log:
|
|
45
|
+
if status_msg.startswith(status_msg_prefix) and status_msg.endswith(status_msg_suffix):
|
|
46
|
+
# found the same operation done on a different model part, hence sending that name
|
|
47
|
+
self.status_msg = status_msg
|
|
48
|
+
full_model_part_name = f"{self.GetRootModelPart().FullName()}.{status_msg.split('#')[1]}"
|
|
49
|
+
Kratos.Logger.PrintInfo("ModelPartUtilities", f"Using \"{full_model_part_name}\" with the same operation instead of suggested model part with name = \"{self.GetRootModelPart().FullName()}.{self.suggested_model_part_name}\".")
|
|
50
|
+
return full_model_part_name
|
|
51
|
+
|
|
52
|
+
# it is not already called for creation. Then put that in the status msg.
|
|
53
|
+
if self.root_model_part.HasSubModelPart(self.suggested_model_part_name):
|
|
54
|
+
# this means, it already has a model part with suggested name, but
|
|
55
|
+
# it does not match the operation identifier. So throw an error
|
|
56
|
+
raise RuntimeError(f"Found an already existing submodel part named \"{self.suggested_model_part_name}\" in {self.root_model_part.FullName()} without the required operation identifier = \"{status_msg_suffix}\".")
|
|
57
|
+
|
|
58
|
+
self.status_msg = f"{status_msg_prefix}{self.suggested_model_part_name}{status_msg_suffix}"
|
|
59
|
+
KratosOA.OptAppModelPartUtils.LogModelPartStatus(self.GetRootModelPart(), self.status_msg)
|
|
60
|
+
return f"{self.GetRootModelPart().FullName()}.{self.suggested_model_part_name}"
|
|
61
|
+
|
|
62
|
+
def GetModelPart(self) -> Kratos.ModelPart:
|
|
63
|
+
model_part_name = self.GetModelPartFullName()
|
|
64
|
+
if self.status_msg == "" or self.model.HasModelPart(model_part_name):
|
|
65
|
+
# if it is already there, that means it is already created. Hence return it or
|
|
66
|
+
# if the self.status_msg == "" means, there is no need to do any model part operations.
|
|
67
|
+
# therefore the model part should exist already.
|
|
68
|
+
return self.model[model_part_name]
|
|
69
|
+
else:
|
|
70
|
+
# the model part with the required operation not found. Hence creating it.
|
|
71
|
+
sub_model_part = self.model.CreateModelPart(model_part_name)
|
|
72
|
+
# now fill the submodel part
|
|
73
|
+
operation_model_parts = [self.model[name] for name in self.list_of_operation_model_part_full_names]
|
|
74
|
+
if self.operation_type == ModelPartOperation.OperationType.UNION:
|
|
75
|
+
Kratos.ModelPartOperationUtilities.Union(sub_model_part, self.root_model_part, operation_model_parts, self.add_neighbours)
|
|
76
|
+
elif self.operation_type == ModelPartOperation.OperationType.INTERSECT:
|
|
77
|
+
Kratos.ModelPartOperationUtilities.Intersect(sub_model_part, self.root_model_part, operation_model_parts, self.add_neighbours)
|
|
78
|
+
|
|
79
|
+
Kratos.Logger.PrintInfo("ModelPartUtilities", f"Created sub model part \"{sub_model_part.FullName()}\".")
|
|
80
|
+
|
|
81
|
+
return sub_model_part
|
|
82
|
+
|
|
83
|
+
class ModelPartUtilities:
|
|
84
|
+
@staticmethod
|
|
85
|
+
def __GenerateUniqueIdentifier(prefix: str, list_of_names: 'list[str]', add_neighbours: bool) -> str:
|
|
86
|
+
if not all([name.find("#") == -1 for name in list_of_names]):
|
|
87
|
+
raise RuntimeError(f"The provided model part names has \"#\" which is invalid. Please remove all occurances of \"#\" character. Provided model part names:\n\t" + "\n\t".join(list_of_names))
|
|
88
|
+
|
|
89
|
+
sorted_names = sorted(list_of_names)
|
|
90
|
+
post_fix = "IN" if add_neighbours else "EN"
|
|
91
|
+
return (f"{prefix}_{post_fix}_" + "_".join(sorted_names)).replace(".", "-")
|
|
92
|
+
|
|
93
|
+
@staticmethod
|
|
94
|
+
def GetMergedMap(input_dict: 'dict[Any, KratosOA.CollectiveExpression]', add_neghbours: bool) -> 'dict[Any, Kratos.ModelPart]':
|
|
95
|
+
result: 'dict[Any, Kratos.ModelPart]' = {}
|
|
96
|
+
for k, v in input_dict.items():
|
|
97
|
+
merging_model_part_names = [container_expression.GetModelPart().FullName() for container_expression in v.GetContainerExpressions()]
|
|
98
|
+
|
|
99
|
+
if not merging_model_part_names:
|
|
100
|
+
raise RuntimeError("Merging requires atleast one model part.")
|
|
101
|
+
|
|
102
|
+
uniqe_identifier_name = ModelPartUtilities.__GenerateUniqueIdentifier("UNION", merging_model_part_names, add_neghbours)
|
|
103
|
+
merged_model_part = ModelPartOperation(v.GetContainerExpressions()[0].GetModelPart().GetModel(), ModelPartOperation.OperationType.UNION, uniqe_identifier_name, merging_model_part_names, add_neghbours).GetModelPart()
|
|
104
|
+
result[k] = merged_model_part
|
|
105
|
+
|
|
106
|
+
return result
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def GetIntersectedMap(main_model_part: Kratos.ModelPart, input_dict: 'dict[Any, Kratos.ModelPart]', add_neghbours: bool) -> 'dict[Any, Kratos.ModelPart]':
|
|
110
|
+
result: 'dict[Any, Kratos.ModelPart]' = {}
|
|
111
|
+
for k, v in input_dict.items():
|
|
112
|
+
intersecting_model_part_names = [main_model_part.FullName(), v.FullName()]
|
|
113
|
+
uniqe_identifier_name = ModelPartUtilities.__GenerateUniqueIdentifier("INTERSECT", intersecting_model_part_names, add_neghbours)
|
|
114
|
+
intersected_model_part = ModelPartOperation(main_model_part.GetModel(), ModelPartOperation.OperationType.INTERSECT, uniqe_identifier_name, intersecting_model_part_names, add_neghbours).GetModelPart()
|
|
115
|
+
result[k] = intersected_model_part
|
|
116
|
+
|
|
117
|
+
return result
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import KratosMultiphysics as Kratos
|
|
2
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
|
|
3
|
+
from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
|
|
4
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import DictLogger
|
|
5
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator
|
|
6
|
+
import numpy
|
|
7
|
+
|
|
8
|
+
import math
|
|
9
|
+
|
|
10
|
+
def CreateLineSearch(parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
|
|
11
|
+
type = parameters["type"].GetString()
|
|
12
|
+
if type == "const_step":
|
|
13
|
+
return ConstStep(parameters, optimization_problem)
|
|
14
|
+
elif type == "BB_step":
|
|
15
|
+
return BBStep(parameters, optimization_problem)
|
|
16
|
+
elif type == "QNBB_step":
|
|
17
|
+
return QNBBStep(parameters, optimization_problem)
|
|
18
|
+
else:
|
|
19
|
+
raise RuntimeError(f"CreateConvergenceCriteria: unsupported convergence type {type}.")
|
|
20
|
+
|
|
21
|
+
class ConstStep():
|
|
22
|
+
@classmethod
|
|
23
|
+
def GetDefaultParameters(cls):
|
|
24
|
+
return Kratos.Parameters("""{
|
|
25
|
+
"type" : "const_step",
|
|
26
|
+
"init_step" : 0,
|
|
27
|
+
"gradient_scaling": ": inf_norm"
|
|
28
|
+
}""")
|
|
29
|
+
|
|
30
|
+
def __init__(self, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
|
|
31
|
+
parameters.ValidateAndAssignDefaults(self.GetDefaultParameters())
|
|
32
|
+
self._init_step = parameters["init_step"].GetDouble()
|
|
33
|
+
self._optimization_problem = optimization_problem
|
|
34
|
+
self._gradient_scaling = parameters["gradient_scaling"].GetString()
|
|
35
|
+
self.unscaled_step = self._init_step
|
|
36
|
+
|
|
37
|
+
def ComputeScaleFactor(self) -> float:
|
|
38
|
+
algorithm_buffered_data = ComponentDataView("algorithm", self._optimization_problem).GetBufferedData()
|
|
39
|
+
|
|
40
|
+
if not algorithm_buffered_data.HasValue("search_direction"):
|
|
41
|
+
raise RuntimeError(f"Algorithm data does not contain computed \"search_direction\".\nData:\n{algorithm_buffered_data}" )
|
|
42
|
+
|
|
43
|
+
search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data["search_direction"]
|
|
44
|
+
if self._gradient_scaling == "inf_norm":
|
|
45
|
+
return numpy.max(numpy.abs(search_direction.data))
|
|
46
|
+
elif self._gradient_scaling == "l2_norm":
|
|
47
|
+
return numpy.linalg.norm(search_direction.data)
|
|
48
|
+
elif self._gradient_scaling == "none":
|
|
49
|
+
return 1.0
|
|
50
|
+
else:
|
|
51
|
+
raise RuntimeError("\"gradient_scaling\" has unknown type.")
|
|
52
|
+
|
|
53
|
+
@time_decorator()
|
|
54
|
+
def ComputeStep(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor:
|
|
55
|
+
norm = self.ComputeScaleFactor()
|
|
56
|
+
if not math.isclose(norm, 0.0, abs_tol=1e-16):
|
|
57
|
+
self.step = self._init_step / norm
|
|
58
|
+
else:
|
|
59
|
+
self.step = self._init_step
|
|
60
|
+
|
|
61
|
+
DictLogger("Line Search info",self.GetInfo())
|
|
62
|
+
|
|
63
|
+
algorithm_buffered_data = ComponentDataView("algorithm", self._optimization_problem).GetBufferedData()
|
|
64
|
+
step = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(algorithm_buffered_data["search_direction"])
|
|
65
|
+
step.data[:] = self.step
|
|
66
|
+
return step
|
|
67
|
+
|
|
68
|
+
def GetInfo(self) -> dict:
|
|
69
|
+
info = {'type': 'constant',
|
|
70
|
+
'unscaled_step': self.unscaled_step,
|
|
71
|
+
'scaled_step': self.step}
|
|
72
|
+
return info
|
|
73
|
+
|
|
74
|
+
class BBStep(ConstStep):
|
|
75
|
+
@classmethod
|
|
76
|
+
def GetDefaultParameters(cls):
|
|
77
|
+
return Kratos.Parameters("""{
|
|
78
|
+
"type" : "BB_step",
|
|
79
|
+
"init_step" : 0,
|
|
80
|
+
"max_step" : 0,
|
|
81
|
+
"gradient_scaling" : "inf_norm"
|
|
82
|
+
}""")
|
|
83
|
+
|
|
84
|
+
def __init__(self, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
|
|
85
|
+
parameters.ValidateAndAssignDefaults(self.GetDefaultParameters())
|
|
86
|
+
self._init_step = parameters["init_step"].GetDouble()
|
|
87
|
+
self._max_step = parameters["max_step"].GetDouble()
|
|
88
|
+
self._optimization_problem = optimization_problem
|
|
89
|
+
self._gradient_scaling = parameters["gradient_scaling"].GetString()
|
|
90
|
+
|
|
91
|
+
@time_decorator()
|
|
92
|
+
def ComputeStep(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor:
|
|
93
|
+
algorithm_buffered_data = ComponentDataView("algorithm", self._optimization_problem).GetBufferedData()
|
|
94
|
+
norm = self.ComputeScaleFactor()
|
|
95
|
+
if math.isclose(norm, 0.0, abs_tol=1e-16):
|
|
96
|
+
norm = 1.0
|
|
97
|
+
if self._optimization_problem.GetStep() == 0:
|
|
98
|
+
self.step = self._init_step / norm
|
|
99
|
+
else:
|
|
100
|
+
current_search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("search_direction", 0)
|
|
101
|
+
previous_search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("search_direction", 1)
|
|
102
|
+
y = previous_search_direction.data - current_search_direction.data
|
|
103
|
+
d: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("control_field_update", 1)
|
|
104
|
+
dy = numpy.inner(d.data[:].ravel(), y.ravel())
|
|
105
|
+
dd = numpy.inner(d.data[:].ravel(), d.data[:].ravel())
|
|
106
|
+
if math.isclose(dy, 0.0, abs_tol=1e-16):
|
|
107
|
+
self.step = self._max_step / norm
|
|
108
|
+
else:
|
|
109
|
+
self.step = abs( dd / dy )
|
|
110
|
+
|
|
111
|
+
if self.step > self._max_step / norm:
|
|
112
|
+
self.step = self._max_step / norm
|
|
113
|
+
|
|
114
|
+
DictLogger("Line Search info",self.GetInfo())
|
|
115
|
+
|
|
116
|
+
algorithm_buffered_data = ComponentDataView("algorithm", self._optimization_problem).GetBufferedData()
|
|
117
|
+
step = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(algorithm_buffered_data["search_direction"])
|
|
118
|
+
step.data[:] = self.step
|
|
119
|
+
return step
|
|
120
|
+
|
|
121
|
+
def GetInfo(self) -> dict:
|
|
122
|
+
info = {'type': 'BB_step',
|
|
123
|
+
'step': self.step,
|
|
124
|
+
'max_step': self._max_step,
|
|
125
|
+
'init_step': self._init_step}
|
|
126
|
+
|
|
127
|
+
return info
|
|
128
|
+
|
|
129
|
+
class QNBBStep(BBStep):
|
|
130
|
+
@time_decorator()
|
|
131
|
+
def ComputeStep(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor:
|
|
132
|
+
algorithm_buffered_data = ComponentDataView("algorithm", self._optimization_problem).GetBufferedData()
|
|
133
|
+
norm = self.ComputeScaleFactor()
|
|
134
|
+
if math.isclose(norm, 0.0, abs_tol=1e-16):
|
|
135
|
+
norm = 1.0
|
|
136
|
+
self.step = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(algorithm_buffered_data.GetValue("search_direction", 0), perform_store_data_recursively=False)
|
|
137
|
+
self.step.data[:] = 0.0
|
|
138
|
+
if not algorithm_buffered_data.HasValue("step_size"):
|
|
139
|
+
algorithm_buffered_data["step_size"] = self.step
|
|
140
|
+
|
|
141
|
+
if self._optimization_problem.GetStep() == 0:
|
|
142
|
+
self.step.data[:] = self._init_step / norm
|
|
143
|
+
else:
|
|
144
|
+
current_search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("search_direction", 0)
|
|
145
|
+
previous_search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("search_direction", 1)
|
|
146
|
+
y = previous_search_direction.data - current_search_direction.data
|
|
147
|
+
d: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("control_field_update", 1)
|
|
148
|
+
d = d.data[:]
|
|
149
|
+
for i in range(len(y)):
|
|
150
|
+
dy = numpy.dot(d[i], y[i])
|
|
151
|
+
dd = numpy.dot(d[i], d[i])
|
|
152
|
+
|
|
153
|
+
if math.isclose(dy, 0.0, abs_tol=1e-16):
|
|
154
|
+
self.step.data[i] = self._max_step / norm
|
|
155
|
+
else:
|
|
156
|
+
self.step.data[i] = abs( dd / dy )
|
|
157
|
+
|
|
158
|
+
if isinstance(d[i], (float, int, numpy.float64)) and self.step.data[i] > self._max_step / norm:
|
|
159
|
+
self.step.data[i] = self._max_step / norm
|
|
160
|
+
elif isinstance(d[i], (numpy.ndarray)) and self.step.data[i][0] > self._max_step / norm:
|
|
161
|
+
self.step.data[i] = self._max_step / norm
|
|
162
|
+
|
|
163
|
+
DictLogger("Line Search info",self.GetInfo())
|
|
164
|
+
self.step.StoreData()
|
|
165
|
+
return self.step
|
|
166
|
+
|
|
167
|
+
def GetInfo(self) -> dict:
|
|
168
|
+
info = {'type': 'QNBB_step',
|
|
169
|
+
# 'max scaled_step': self.step.max(),
|
|
170
|
+
'max_step': self._max_step,
|
|
171
|
+
'init_step': self._init_step}
|
|
172
|
+
|
|
173
|
+
return info
|